Passed
Pull Request — develop (#92)
by Felipe
04:25
created

DisplayController::doBrowseFK()   B

Complexity

Conditions 4

Size

Total Lines 46
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 29
nop 0
dl 0
loc 46
rs 8.6315
c 0
b 0
f 0
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
/**
10
 * Base controller class.
11
 */
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...
12
class DisplayController extends BaseController
13
{
14
    public $controller_name = 'DisplayController';
15
16
    /**
17
     * Default method to render the controller according to the action parameter.
18
     */
19
    public function render()
20
    {
21
        $conf           = $this->conf;
0 ignored issues
show
Unused Code introduced by
The assignment to $conf is dead and can be removed.
Loading history...
22
        $this->misc     = $this->misc;
23
        $lang           = $this->lang;
24
        $plugin_manager = $this->plugin_manager;
1 ignored issue
show
Unused Code introduced by
The assignment to $plugin_manager is dead and can be removed.
Loading history...
25
        $data           = $this->misc->getDatabaseAccessor();
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
26
        $action         = $this->action;
27
28
        if ('dobrowsefk' == $action) {
29
            return $this->doBrowseFK();
30
        }
31
32
        set_time_limit(0);
33
34
        $scripts = '<script src="' . \SUBFOLDER . '/js/display.js" type="text/javascript"></script>';
35
36
        $scripts .= '<script type="text/javascript">' . "\n";
37
        $scripts .= "var Display = {\n";
38
        $scripts .= "errmsg: '" . str_replace("'", "\\'", $lang['strconnectionfail']) . "'\n";
39
        $scripts .= "};\n";
40
        $scripts .= '</script>' . "\n";
41
42
        $footer_template = 'footer.twig';
43
        $header_template = 'header.twig';
44
45
        ob_start();
46
        switch ($action) {
47
            case 'editrow':
48
                $header_template = 'header_sqledit.twig';
49
                $footer_template = 'footer_sqledit.twig';
50
                if (isset($_POST['save'])) {
51
                    $this->doEditRow(false);
52
                } else {
53
                    $this->doBrowse();
54
                }
55
56
                break;
57
            case 'confeditrow':
58
                $this->doEditRow(true);
59
60
                break;
61
            case 'delrow':
62
                $header_template = 'header_sqledit.twig';
63
                $footer_template = 'footer_sqledit.twig';
64
                if (isset($_POST['yes'])) {
65
                    $this->doDelRow(false);
66
                } else {
67
                    $this->doBrowse();
68
                }
69
70
                break;
71
            case 'confdelrow':
72
                $this->doDelRow(true);
73
74
                break;
75
            default:
76
                $header_template = 'header_sqledit.twig';
77
                $footer_template = 'footer_sqledit.twig';
78
                $this->doBrowse();
79
80
                break;
81
        }
82
        $output = ob_get_clean();
83
84
        // Set the title based on the subject of the request
85
        if (isset($_REQUEST['subject'], $_REQUEST[$_REQUEST['subject']])) {
86
            if ('table' == $_REQUEST['subject']) {
87
                $this->printHeader($lang['strtables'] . ': ' . $_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
88
            } elseif ('view' == $_REQUEST['subject']) {
89
                $this->printHeader($lang['strviews'] . ': ' . $_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
90
            } elseif ('matview' == $_REQUEST['subject']) {
91
                $this->printHeader('M' . $lang['strviews'] . ': ' . $_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
92
            } elseif ('column' == $_REQUEST['subject']) {
93
                $this->printHeader($lang['strcolumn'] . ': ' . $_REQUEST[$_REQUEST['subject']], $scripts, true, $header_template);
94
            }
95
        } else {
96
            $this->printHeader($lang['strqueryresults'], $scripts, true, $header_template);
97
        }
98
99
        $this->printBody();
100
101
        echo $output;
102
103
        $this->printFooter(true, $footer_template);
104
    }
105
106
    /**
107
     * Displays requested data.
108
     *
109
     * @param mixed $msg
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
110
     */
111
    public function doBrowse($msg = '')
112
    {
113
        $conf           = $this->conf;
114
        $this->misc     = $this->misc;
115
        $lang           = $this->lang;
116
        $plugin_manager = $this->plugin_manager;
117
        $data           = $this->misc->getDatabaseAccessor();
118
119
        $save_history = false;
120
        // If current page is not set, default to first page
121
        if (!isset($_REQUEST['page'])) {
122
            $_REQUEST['page'] = 1;
123
        }
124
125
        if (!isset($_REQUEST['nohistory'])) {
126
            $save_history = true;
127
        }
128
129
        if (isset($_REQUEST['subject'])) {
130
            $subject = $_REQUEST['subject'];
131
            if (isset($_REQUEST[$subject])) {
132
                $object = $_REQUEST[$subject];
133
            }
134
        } else {
135
            $subject = '';
136
        }
137
138
        $this->printTrail(isset($subject) ? $subject : 'database');
139
        $this->printTabs($subject, 'browse');
140
141
        // This code is used when browsing FK in pure-xHTML (without js)
142
        if (isset($_REQUEST['fkey'])) {
143
            $ops = [];
144
            foreach ($_REQUEST['fkey'] as $x => $y) {
145
                $ops[$x] = '=';
146
            }
147
            $query             = $data->getSelectSQL($_REQUEST['table'], [], $_REQUEST['fkey'], $ops);
148
            $_REQUEST['query'] = $query;
149
        }
150
151
        if (isset($object)) {
152
            if (isset($_REQUEST['query'])) {
153
                $_SESSION['sqlquery'] = $_REQUEST['query'];
154
                $this->printTitle($lang['strselect']);
155
                $type = 'SELECT';
156
            } else {
157
                $type = 'TABLE';
158
            }
159
        } else {
160
            $this->printTitle($lang['strqueryresults']);
161
            // we comes from sql.php, $_SESSION['sqlquery'] has been set there
162
            $type = 'QUERY';
163
        }
164
165
        $this->printMsg($msg);
166
167
        // If 'sortkey' is not set, default to ''
168
        if (!isset($_REQUEST['sortkey'])) {
169
            $_REQUEST['sortkey'] = '';
170
        }
171
172
        // If 'sortdir' is not set, default to ''
173
        if (!isset($_REQUEST['sortdir'])) {
174
            $_REQUEST['sortdir'] = '';
175
        }
176
177
        // If 'strings' is not set, default to collapsed
178
        if (!isset($_REQUEST['strings'])) {
179
            $_REQUEST['strings'] = 'collapsed';
180
        }
181
182
        // Fetch unique row identifier, if this is a table browse request.
183
        if (isset($object)) {
184
            $key = $data->getRowIdentifier($object);
185
        } else {
186
            $key = [];
187
        }
188
189
        // Set the schema search path
190
        if (isset($_REQUEST['search_path'])) {
191
            if (0 != $data->setSearchPath(array_map('trim', explode(',', $_REQUEST['search_path'])))) {
192
                return;
193
            }
194
        }
195
196
        try {
197
            // Retrieve page from query.  $max_pages is returned by reference.
198
            $rs = $data->browseQuery(
199
                $type,
200
                isset($object) ? $object : null,
201
                isset($_SESSION['sqlquery']) ? $_SESSION['sqlquery'] : null,
202
                $_REQUEST['sortkey'],
203
                $_REQUEST['sortdir'],
204
                $_REQUEST['page'],
205
                $conf['max_rows'],
206
                $max_pages
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $max_pages seems to be never defined.
Loading history...
207
            );
208
        } catch (\PHPPgAdmin\ADOdbException $e) {
209
            return;
210
        }
211
212
        $fkey_information = $this->getFKInfo();
213
214
        // Build strings for GETs in array
215
        $_gets = [
216
            'server'   => $_REQUEST['server'],
217
            'database' => $_REQUEST['database'],
218
        ];
219
220
        if (isset($_REQUEST['schema'])) {
221
            $_gets['schema'] = $_REQUEST['schema'];
222
        }
223
224
        if (isset($object)) {
225
            $_gets[$subject] = $object;
226
        }
227
228
        if (isset($subject)) {
229
            $_gets['subject'] = $subject;
230
        }
231
232
        if (isset($_REQUEST['query'])) {
233
            $_gets['query'] = $_REQUEST['query'];
234
        }
235
236
        if (isset($_REQUEST['count'])) {
237
            $_gets['count'] = $_REQUEST['count'];
238
        }
239
240
        if (isset($_REQUEST['return'])) {
241
            $_gets['return'] = $_REQUEST['return'];
242
        }
243
244
        if (isset($_REQUEST['search_path'])) {
245
            $_gets['search_path'] = $_REQUEST['search_path'];
246
        }
247
248
        if (isset($_REQUEST['table'])) {
249
            $_gets['table'] = $_REQUEST['table'];
250
        }
251
252
        if (isset($_REQUEST['sortkey'])) {
253
            $_gets['sortkey'] = $_REQUEST['sortkey'];
254
        }
255
256
        if (isset($_REQUEST['sortdir'])) {
257
            $_gets['sortdir'] = $_REQUEST['sortdir'];
258
        }
259
260
        if (isset($_REQUEST['nohistory'])) {
261
            $_gets['nohistory'] = $_REQUEST['nohistory'];
262
        }
263
264
        $_gets['strings'] = $_REQUEST['strings'];
265
266
        if ($save_history && is_object($rs) && ('QUERY' == $type)) {
267
            //{
268
            $this->misc->saveScriptHistory($_REQUEST['query']);
269
        }
270
271
        if (isset($_REQUEST['query'])) {
272
            $query = $_REQUEST['query'];
273
        } else {
274
            $query = "SELECT * FROM {$_REQUEST['schema']}";
275
            if ('matview' == $_REQUEST['subject']) {
276
                $query = "{$query}.{$_REQUEST['matview']};";
277
            } elseif ('view' == $_REQUEST['subject']) {
278
                $query = "{$query}.{$_REQUEST['view']};";
279
            } else {
280
                $query = "{$query}.{$_REQUEST['table']};";
281
            }
282
        }
283
        //$query = isset($_REQUEST['query'])? $_REQUEST['query'] : "select * from {$_REQUEST['schema']}.{$_REQUEST['table']};";
284
        $this->prtrace($query);
285
        //die(htmlspecialchars($query));
286
287
        echo '<form method="post" id="sqlform" action="' . $_SERVER['REQUEST_URI'] . '">';
288
        echo '<textarea width="90%" name="query"  id="query" rows="5" cols="100" resizable="true">';
289
290
        echo htmlspecialchars($query);
291
        echo '</textarea><br><input type="submit"/></form>';
292
293
        if (is_object($rs) && $rs->recordCount() > 0) {
294
            // Show page navigation
295
            $this->misc->printPages($_REQUEST['page'], $max_pages, $_gets);
296
297
            echo "<table id=\"data\">\n<tr>";
298
299
            // Check that the key is actually in the result set.  This can occur for select
300
            // operations where the key fields aren't part of the select.  XXX:  We should
301
            // be able to support this, somehow.
302
            foreach ($key as $v) {
303
                // If a key column is not found in the record set, then we
304
                // can't use the key.
305
                if (!in_array($v, array_keys($rs->fields), true)) {
306
                    $key = [];
307
308
                    break;
309
                }
310
            }
311
312
            $buttons = [
313
                'edit'   => [
314
                    'content' => $lang['stredit'],
315
                    'attr'    => [
316
                        'href' => [
317
                            'url'     => 'display.php',
318
                            'urlvars' => array_merge([
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...
319
                                'action'  => 'confeditrow',
320
                                'strings' => $_REQUEST['strings'],
321
                                'page'    => $_REQUEST['page'],
322
                            ], $_gets),
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...
323
                        ],
324
                    ],
325
                ],
326
                'delete' => [
327
                    'content' => $lang['strdelete'],
328
                    'attr'    => [
329
                        'href' => [
330
                            'url'     => 'display.php',
331
                            'urlvars' => array_merge([
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...
332
                                'action'  => 'confdelrow',
333
                                'strings' => $_REQUEST['strings'],
334
                                'page'    => $_REQUEST['page'],
335
                            ], $_gets),
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...
336
                        ],
337
                    ],
338
                ],
339
            ];
340
            $actions = [
341
                'actionbuttons' => &$buttons,
342
                'place'         => 'display-browse',
343
            ];
344
            $plugin_manager->do_hook('actionbuttons', $actions);
345
346
            foreach (array_keys($actions['actionbuttons']) as $action) {
347
                $actions['actionbuttons'][$action]['attr']['href']['urlvars'] = array_merge(
348
                    $actions['actionbuttons'][$action]['attr']['href']['urlvars'],
349
                    $_gets
350
                );
351
            }
352
353
            $edit_params = isset($actions['actionbuttons']['edit']) ?
354
            $actions['actionbuttons']['edit'] : [];
355
            $delete_params = isset($actions['actionbuttons']['delete']) ?
356
            $actions['actionbuttons']['delete'] : [];
357
358
            // Display edit and delete actions if we have a key
359
            $colspan = count($buttons);
360
            if ($colspan > 0 and count($key) > 0) {
361
                echo "<th colspan=\"{$colspan}\" class=\"data\">{$lang['stractions']}</th>" . "\n";
362
            }
363
364
            // we show OIDs only if we are in TABLE or SELECT type browsing
365
            $this->printTableHeaderCells($rs, $_gets, isset($object));
366
367
            echo '</tr>' . "\n";
368
369
            $i = 0;
370
            reset($rs->fields);
371
            while (!$rs->EOF) {
372
                $id = (0 == ($i % 2) ? '1' : '2');
373
                echo "<tr class=\"data{$id}\">" . "\n";
374
                // Display edit and delete links if we have a key
375
                if ($colspan > 0 and count($key) > 0) {
376
                    $keys_array = [];
377
                    $has_nulls  = false;
378
                    foreach ($key as $v) {
379
                        if (null === $rs->fields[$v]) {
380
                            $has_nulls = true;
381
382
                            break;
383
                        }
384
                        $keys_array["key[{$v}]"] = $rs->fields[$v];
385
                    }
386
                    if ($has_nulls) {
387
                        echo "<td colspan=\"{$colspan}\">&nbsp;</td>" . "\n";
388
                    } else {
389
                        if (isset($actions['actionbuttons']['edit'])) {
390
                            $actions['actionbuttons']['edit']                            = $edit_params;
391
                            $actions['actionbuttons']['edit']['attr']['href']['urlvars'] = array_merge(
392
                                $actions['actionbuttons']['edit']['attr']['href']['urlvars'],
393
                                $keys_array
394
                            );
395
                        }
396
397
                        if (isset($actions['actionbuttons']['delete'])) {
398
                            $actions['actionbuttons']['delete']                            = $delete_params;
399
                            $actions['actionbuttons']['delete']['attr']['href']['urlvars'] = array_merge(
400
                                $actions['actionbuttons']['delete']['attr']['href']['urlvars'],
401
                                $keys_array
402
                            );
403
                        }
404
405
                        foreach ($actions['actionbuttons'] as $action) {
406
                            echo "<td class=\"opbutton{$id}\">";
407
                            $this->printLink($action, true, __METHOD__);
408
                            echo '</td>' . "\n";
409
                        }
410
                    }
411
                }
412
413
                $this->printTableRowCells($rs, $fkey_information, isset($object));
414
415
                echo '</tr>' . "\n";
416
                $rs->moveNext();
417
                ++$i;
418
            }
419
            echo '</table>' . "\n";
420
421
            echo '<p>', $rs->recordCount(), " {$lang['strrows']}</p>" . "\n";
422
            // Show page navigation
423
            $this->misc->printPages($_REQUEST['page'], $max_pages, $_gets);
424
        } else {
425
            echo "<p>{$lang['strnodata']}</p>" . "\n";
426
        }
427
428
        // Navigation links
429
        $navlinks = [];
430
431
        $fields = [
432
            'server'   => $_REQUEST['server'],
433
            'database' => $_REQUEST['database'],
434
        ];
435
436
        if (isset($_REQUEST['schema'])) {
437
            $fields['schema'] = $_REQUEST['schema'];
438
        }
439
440
        // Return
441
        if (isset($_REQUEST['return'])) {
442
            $urlvars = $this->misc->getSubjectParams($_REQUEST['return']);
443
444
            $navlinks['back'] = [
445
                'attr'    => [
446
                    'href' => [
447
                        'url'     => $urlvars['url'],
448
                        'urlvars' => $urlvars['params'],
449
                    ],
450
                ],
451
                'content' => $lang['strback'],
452
            ];
453
        }
454
455
        // Edit SQL link
456
        if ('QUERY' == $type) {
457
            $navlinks['edit'] = [
458
                'attr'    => [
459
                    'href' => [
460
                        'url'     => 'database.php',
461
                        'urlvars' => array_merge($fields, [
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...
462
                            'action'   => 'sql',
463
                            'paginate' => 'on',
464
                        ]),
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...
465
                    ],
466
                ],
467
                'content' => $lang['streditsql'],
468
            ];
469
        }
470
471
        // Expand/Collapse
472
        if ('expanded' == $_REQUEST['strings']) {
473
            $navlinks['collapse'] = [
474
                'attr'    => [
475
                    'href' => [
476
                        'url'     => 'display.php',
477
                        'urlvars' => array_merge(
478
                            $_gets,
479
                            [
480
                                'strings' => 'collapsed',
481
                                'page'    => $_REQUEST['page'],
482
                            ]
483
                        ),
484
                    ],
485
                ],
486
                'content' => $lang['strcollapse'],
487
            ];
488
        } else {
489
            $navlinks['collapse'] = [
490
                'attr'    => [
491
                    'href' => [
492
                        'url'     => 'display.php',
493
                        'urlvars' => array_merge(
494
                            $_gets,
495
                            [
496
                                'strings' => 'expanded',
497
                                'page'    => $_REQUEST['page'],
498
                            ]
499
                        ),
500
                    ],
501
                ],
502
                'content' => $lang['strexpand'],
503
            ];
504
        }
505
506
        // Create view and download
507
        if (isset($_REQUEST['query'], $rs) && is_object($rs) && $rs->recordCount() > 0) {
508
            // Report views don't set a schema, so we need to disable create view in that case
509
            if (isset($_REQUEST['schema'])) {
510
                $navlinks['createview'] = [
511
                    'attr'    => [
512
                        'href' => [
513
                            'url'     => 'views.php',
514
                            'urlvars' => array_merge($fields, [
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...
515
                                'action'         => 'create',
516
                                'formDefinition' => $_REQUEST['query'],
517
                            ]),
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...
518
                        ],
519
                    ],
520
                    'content' => $lang['strcreateview'],
521
                ];
522
            }
523
524
            $urlvars = [];
525
            if (isset($_REQUEST['search_path'])) {
526
                $urlvars['search_path'] = $_REQUEST['search_path'];
527
            }
528
529
            $navlinks['download'] = [
530
                'attr'    => [
531
                    'href' => [
532
                        'url'     => 'dataexport.php',
533
                        'urlvars' => array_merge($fields, $urlvars),
534
                    ],
535
                ],
536
                'content' => $lang['strdownload'],
537
            ];
538
        }
539
540
        // Insert
541
        if (isset($object) && (isset($subject) && 'table' == $subject)) {
542
            $navlinks['insert'] = [
543
                'attr'    => [
544
                    'href' => [
545
                        'url'     => 'tables.php',
546
                        'urlvars' => array_merge($fields, [
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...
547
                            'action' => 'confinsertrow',
548
                            'table'  => $object,
549
                        ]),
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...
550
                    ],
551
                ],
552
                'content' => $lang['strinsert'],
553
            ];
554
        }
555
556
        // Refresh
557
        $navlinks['refresh'] = [
558
            'attr'    => [
559
                'href' => [
560
                    'url'     => 'display.php',
561
                    'urlvars' => array_merge(
562
                        $_gets,
563
                        [
564
                            'strings' => $_REQUEST['strings'],
565
                            'page'    => $_REQUEST['page'],
566
                        ]
567
                    ),
568
                ],
569
            ],
570
            'content' => $lang['strrefresh'],
571
        ];
572
573
        $this->printNavLinks($navlinks, 'display-browse', get_defined_vars());
574
    }
575
576
    /**
577
     * Show confirmation of edit and perform actual update.
578
     *
579
     * @param mixed $confirm
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
580
     * @param mixed $msg
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
581
     */
582
    public function doEditRow($confirm, $msg = '')
583
    {
584
        $lang = $this->lang;
585
        $data = $this->misc->getDatabaseAccessor();
586
587
        if (is_array($_REQUEST['key'])) {
588
            $key = $_REQUEST['key'];
589
        } else {
590
            $key = unserialize(urldecode($_REQUEST['key']));
591
        }
592
593
        if ($confirm) {
594
            $this->printTrail($_REQUEST['subject']);
595
            $this->printTitle($lang['streditrow']);
596
            $this->printMsg($msg);
597
598
            $attrs = $data->getTableAttributes($_REQUEST['table']);
599
            $rs    = $data->browseRow($_REQUEST['table'], $key);
600
601
            if (('disable' != $conf['autocomplete'])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $conf does not exist. Did you maybe mean $confirm?
Loading history...
602
                $fksprops = $this->misc->getAutocompleteFKProperties($_REQUEST['table']);
603
                if (false !== $fksprops) {
604
                    echo $fksprops['code'];
605
                }
606
            } else {
607
                $fksprops = false;
608
            }
609
610
            echo '<form action="' . \SUBFOLDER . '/src/views/display.php" method="post" id="ac_form">' . "\n";
611
612
            /*echo '<p>';
613
            if (!$error) {
614
            echo "<input type=\"submit\" name=\"save\" accesskey=\"r\" value=\"{$lang['strsave']}\" />" . "\n";
615
            }
616
617
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
618
619
            echo '</p>' . "\n";*/
620
621
            $elements = 0;
622
            $error    = true;
623
            if (1 == $rs->recordCount() && $attrs->recordCount() > 0) {
624
                echo '<table>' . "\n";
625
626
                // Output table header
627
                echo "<tr><th class=\"data\">{$lang['strcolumn']}</th><th class=\"data\">{$lang['strtype']}</th>";
628
                echo "<th class=\"data\">{$lang['strformat']}</th>" . "\n";
629
                echo "<th class=\"data\">{$lang['strnull']}</th><th class=\"data\">{$lang['strvalue']}</th></tr>";
630
631
                $i = 0;
632
                while (!$attrs->EOF) {
633
                    $attrs->fields['attnotnull'] = $data->phpBool($attrs->fields['attnotnull']);
634
                    $id                          = (0 == ($i % 2) ? '1' : '2');
635
636
                    // Initialise variables
637
                    if (!isset($_REQUEST['format'][$attrs->fields['attname']])) {
638
                        $_REQUEST['format'][$attrs->fields['attname']] = 'VALUE';
639
                    }
640
641
                    echo "<tr class=\"data{$id}\">" . "\n";
642
                    echo '<td style="white-space:nowrap;">', $this->misc->printVal($attrs->fields['attname']), '</td>';
643
                    echo '<td style="white-space:nowrap;">' . "\n";
644
                    echo $this->misc->printVal($data->formatType($attrs->fields['type'], $attrs->fields['atttypmod']));
645
                    echo '<input type="hidden" name="types[', htmlspecialchars($attrs->fields['attname']), ']" value="',
646
                    htmlspecialchars($attrs->fields['type']), '" /></td>';
647
                    ++$elements;
648
                    echo '<td style="white-space:nowrap;">' . "\n";
649
                    echo '<select name="format[' . htmlspecialchars($attrs->fields['attname']), ']">' . "\n";
650
                    echo '<option value="VALUE"', ($_REQUEST['format'][$attrs->fields['attname']] == 'VALUE') ? ' selected="selected"' : '', ">{$lang['strvalue']}</option>" . "\n";
651
                    $selected = ($_REQUEST['format'][$attrs->fields['attname']] == 'EXPRESSION') ? ' selected="selected"' : '';
652
                    echo '<option value="EXPRESSION"' . $selected . ">{$lang['strexpression']}</option>" . "\n";
653
                    echo "</select>\n</td>" . "\n";
654
                    ++$elements;
655
                    echo '<td style="white-space:nowrap;">';
656
                    // Output null box if the column allows nulls (doesn't look at CHECKs or ASSERTIONS)
657
                    if (!$attrs->fields['attnotnull']) {
658
                        // Set initial null values
659
                        if ('confeditrow' == $_REQUEST['action'] && null === $rs->fields[$attrs->fields['attname']]) {
660
                            $_REQUEST['nulls'][$attrs->fields['attname']] = 'on';
661
                        }
662
                        echo "<label><span><input type=\"checkbox\" name=\"nulls[{$attrs->fields['attname']}]\"",
663
                        isset($_REQUEST['nulls'][$attrs->fields['attname']]) ? ' checked="checked"' : '', ' /></span></label></td>' . "\n";
664
                        ++$elements;
665
                    } else {
666
                        echo '&nbsp;</td>';
667
                    }
668
669
                    echo "<td id=\"row_att_{$attrs->fields['attnum']}\" style=\"white-space:nowrap;\">";
670
671
                    $extras = [];
672
673
                    // If the column allows nulls, then we put a JavaScript action on the data field to unset the
674
                    // NULL checkbox as soon as anything is entered in the field.  We use the $elements variable to
675
                    // keep track of which element offset we're up to.  We can't refer to the null checkbox by name
676
                    // as it contains '[' and ']' characters.
677
                    if (!$attrs->fields['attnotnull']) {
678
                        $extras['onChange'] = 'elements[' . ($elements - 1) . '].checked = false;';
679
                    }
680
681
                    if ((false !== $fksprops) && isset($fksprops['byfield'][$attrs->fields['attnum']])) {
682
                        $extras['id']           = "attr_{$attrs->fields['attnum']}";
683
                        $extras['autocomplete'] = 'off';
684
                    }
685
686
                    echo $data->printField("values[{$attrs->fields['attname']}]", $rs->fields[$attrs->fields['attname']], $attrs->fields['type'], $extras);
687
688
                    echo '</td>';
689
                    ++$elements;
690
                    echo '</tr>' . "\n";
691
                    ++$i;
692
                    $attrs->moveNext();
693
                }
694
                echo '</table>' . "\n";
695
696
                $error = false;
697
            } elseif (1 != $rs->recordCount()) {
698
                echo "<p>{$lang['strrownotunique']}</p>" . "\n";
699
            } else {
700
                echo "<p>{$lang['strinvalidparam']}</p>" . "\n";
701
            }
702
703
            echo '<input type="hidden" name="action" value="editrow" />' . "\n";
704
            echo $this->misc->form;
705
            if (isset($_REQUEST['table'])) {
706
                echo '<input type="hidden" name="table" value="', htmlspecialchars($_REQUEST['table']), '" />' . "\n";
707
            }
708
709
            if (isset($_REQUEST['subject'])) {
710
                echo '<input type="hidden" name="subject" value="', htmlspecialchars($_REQUEST['subject']), '" />' . "\n";
711
            }
712
713
            if (isset($_REQUEST['query'])) {
714
                echo '<input type="hidden" name="query" value="', htmlspecialchars($_REQUEST['query']), '" />' . "\n";
715
            }
716
717
            if (isset($_REQUEST['count'])) {
718
                echo '<input type="hidden" name="count" value="', htmlspecialchars($_REQUEST['count']), '" />' . "\n";
719
            }
720
721
            if (isset($_REQUEST['return'])) {
722
                echo '<input type="hidden" name="return" value="', htmlspecialchars($_REQUEST['return']), '" />' . "\n";
723
            }
724
725
            echo '<input type="hidden" name="page" value="', htmlspecialchars($_REQUEST['page']), '" />' . "\n";
726
            echo '<input type="hidden" name="sortkey" value="', htmlspecialchars($_REQUEST['sortkey']), '" />' . "\n";
727
            echo '<input type="hidden" name="sortdir" value="', htmlspecialchars($_REQUEST['sortdir']), '" />' . "\n";
728
            echo '<input type="hidden" name="strings" value="', htmlspecialchars($_REQUEST['strings']), '" />' . "\n";
729
            echo '<input type="hidden" name="key" value="', htmlspecialchars(urlencode(serialize($key))), '" />' . "\n";
730
            echo '<p>';
731
            if (!$error) {
732
                echo "<input type=\"submit\" name=\"save\" accesskey=\"r\" value=\"{$lang['strsave']}\" />" . "\n";
733
            }
734
735
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
736
737
            if (false !== $fksprops) {
738
                if ('default off' != $conf['autocomplete']) {
739
                    echo "<input type=\"checkbox\" id=\"no_ac\" value=\"1\" checked=\"checked\" /><label for=\"no_ac\">{$lang['strac']}</label>" . "\n";
740
                } else {
741
                    echo "<input type=\"checkbox\" id=\"no_ac\" value=\"0\" /><label for=\"no_ac\">{$lang['strac']}</label>" . "\n";
742
                }
743
            }
744
745
            echo '</p>' . "\n";
746
            echo '</form>' . "\n";
747
        } else {
748
            if (!isset($_POST['values'])) {
749
                $_POST['values'] = [];
750
            }
751
752
            if (!isset($_POST['nulls'])) {
753
                $_POST['nulls'] = [];
754
            }
755
756
            $status = $data->editRow(
757
                $_POST['table'],
758
                $_POST['values'],
759
                $_POST['nulls'],
760
                $_POST['format'],
761
                $_POST['types'],
762
                $key
763
            );
764
            if (0 == $status) {
765
                $this->doBrowse($lang['strrowupdated']);
766
            } elseif ($status == -2) {
767
                $this->doEditRow(true, $lang['strrownotunique']);
768
            } else {
769
                $this->doEditRow(true, $lang['strrowupdatedbad']);
770
            }
771
        }
772
    }
773
774
    /**
775
     * Show confirmation of drop and perform actual drop.
776
     *
777
     * @param mixed $confirm
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
778
     */
779
    public function doDelRow($confirm)
780
    {
781
        $lang = $this->lang;
782
        $data = $this->misc->getDatabaseAccessor();
783
784
        if ($confirm) {
785
            $this->printTrail($_REQUEST['subject']);
786
            $this->printTitle($lang['strdeleterow']);
787
788
            $rs = $data->browseRow($_REQUEST['table'], $_REQUEST['key']);
789
790
            echo '<form action="' . \SUBFOLDER . '/src/views/display.php" method="post">' . "\n";
791
            echo $this->misc->form;
792
793
            if (1 == $rs->recordCount()) {
794
                echo "<p>{$lang['strconfdeleterow']}</p>" . "\n";
795
796
                $fkinfo = [];
797
                echo '<table><tr>';
798
                $this->printTableHeaderCells($rs, false, true);
799
                echo '</tr>';
800
                echo '<tr class="data1">' . "\n";
801
                $this->printTableRowCells($rs, $fkinfo, true);
802
                echo '</tr>' . "\n";
803
                echo '</table>' . "\n";
804
                echo '<br />' . "\n";
805
806
                echo '<input type="hidden" name="action" value="delrow" />' . "\n";
807
                echo "<input type=\"submit\" name=\"yes\" value=\"{$lang['stryes']}\" />" . "\n";
808
                echo "<input type=\"submit\" name=\"no\" value=\"{$lang['strno']}\" />" . "\n";
809
            } elseif (1 != $rs->recordCount()) {
810
                echo "<p>{$lang['strrownotunique']}</p>" . "\n";
811
                echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
812
            } else {
813
                echo "<p>{$lang['strinvalidparam']}</p>" . "\n";
814
                echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />" . "\n";
815
            }
816
            if (isset($_REQUEST['table'])) {
817
                echo '<input type="hidden" name="table" value="', htmlspecialchars($_REQUEST['table']), '" />' . "\n";
818
            }
819
820
            if (isset($_REQUEST['subject'])) {
821
                echo '<input type="hidden" name="subject" value="', htmlspecialchars($_REQUEST['subject']), '" />' . "\n";
822
            }
823
824
            if (isset($_REQUEST['query'])) {
825
                echo '<input type="hidden" name="query" value="', htmlspecialchars($_REQUEST['query']), '" />' . "\n";
826
            }
827
828
            if (isset($_REQUEST['count'])) {
829
                echo '<input type="hidden" name="count" value="', htmlspecialchars($_REQUEST['count']), '" />' . "\n";
830
            }
831
832
            if (isset($_REQUEST['return'])) {
833
                echo '<input type="hidden" name="return" value="', htmlspecialchars($_REQUEST['return']), '" />' . "\n";
834
            }
835
836
            echo '<input type="hidden" name="page" value="', htmlspecialchars($_REQUEST['page']), '" />' . "\n";
837
            echo '<input type="hidden" name="sortkey" value="', htmlspecialchars($_REQUEST['sortkey']), '" />' . "\n";
838
            echo '<input type="hidden" name="sortdir" value="', htmlspecialchars($_REQUEST['sortdir']), '" />' . "\n";
839
            echo '<input type="hidden" name="strings" value="', htmlspecialchars($_REQUEST['strings']), '" />' . "\n";
840
            echo '<input type="hidden" name="key" value="', htmlspecialchars(urlencode(serialize($_REQUEST['key']))), '" />' . "\n";
841
            echo '</form>' . "\n";
842
        } else {
843
            $status = $data->deleteRow($_POST['table'], unserialize(urldecode($_POST['key'])));
844
            if (0 == $status) {
845
                $this->doBrowse($lang['strrowdeleted']);
846
            } elseif ($status == -2) {
847
                $this->doBrowse($lang['strrownotunique']);
848
            } else {
849
                $this->doBrowse($lang['strrowdeletedbad']);
850
            }
851
        }
852
    }
853
854
    /**
855
     * build & return the FK information data structure
1 ignored issue
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
856
     * used when deciding if a field should have a FK link or not.
857
     *
858
     * @return [type] [description]
859
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
860
    public function &getFKInfo()
861
    {
862
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
863
        $data = $this->misc->getDatabaseAccessor();
864
865
        // Get the foreign key(s) information from the current table
866
        $fkey_information = ['byconstr' => [], 'byfield' => []];
867
868
        if (isset($_REQUEST['table'])) {
869
            $constraints = $data->getConstraintsWithFields($_REQUEST['table']);
870
            if ($constraints->recordCount() > 0) {
871
                $fkey_information['common_url'] = $this->misc->getHREF('schema') . '&amp;subject=table';
872
873
                // build the FK constraints data structure
874
                while (!$constraints->EOF) {
875
                    $constr = &$constraints->fields;
876
                    if ('f' == $constr['contype']) {
877
                        if (!isset($fkey_information['byconstr'][$constr['conid']])) {
878
                            $fkey_information['byconstr'][$constr['conid']] = [
879
                                'url_data' => 'table=' . urlencode($constr['f_table']) . '&amp;schema=' . urlencode($constr['f_schema']),
880
                                'fkeys'    => [],
881
                                'consrc'   => $constr['consrc'],
882
                            ];
883
                        }
884
885
                        $fkey_information['byconstr'][$constr['conid']]['fkeys'][$constr['p_field']] = $constr['f_field'];
886
887
                        if (!isset($fkey_information['byfield'][$constr['p_field']])) {
888
                            $fkey_information['byfield'][$constr['p_field']] = [];
889
                        }
890
891
                        $fkey_information['byfield'][$constr['p_field']][] = $constr['conid'];
892
                    }
893
                    $constraints->moveNext();
894
                }
895
            }
896
        }
897
898
        return $fkey_information;
899
    }
900
901
    /**
902
     * Print table header cells.
903
     *
904
     * @param $args - associative array for sort link parameters
905
     * @param mixed $withOid
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Doc comment for parameter $withOid does not match actual variable name $args
Loading history...
906
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment - at position 0 could not be parsed: Unknown type name '-' at position 0 in -.
Loading history...
907
    public function printTableHeaderCells(&$rs, $args, $withOid)
908
    {
909
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
910
        $data = $this->misc->getDatabaseAccessor();
911
        $j    = 0;
912
913
        foreach ($rs->fields as $k => $v) {
914
            if (($k === $data->id) && (!($withOid && $conf['show_oids']))) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $conf seems to be never defined.
Loading history...
915
                ++$j;
916
917
                continue;
918
            }
919
            $finfo = $rs->fetchField($j);
920
921
            if (false === $args) {
922
                echo '<th class="data">', $this->misc->printVal($finfo->name), '</th>' . "\n";
923
            } else {
924
                $args['page']    = $_REQUEST['page'];
925
                $args['sortkey'] = $j + 1;
926
                // Sort direction opposite to current direction, unless it's currently ''
927
                $args['sortdir'] = (
928
                    'asc' == $_REQUEST['sortdir']
929
                    and $_REQUEST['sortkey'] == ($j + 1)
930
                ) ? 'desc' : 'asc';
931
932
                $sortLink = http_build_query($args);
933
934
                echo "<th class=\"data\"><a href=\"?{$sortLink}\">"
935
                , $this->misc->printVal($finfo->name);
936
                if ($_REQUEST['sortkey'] == ($j + 1)) {
937
                    if ('asc' == $_REQUEST['sortdir']) {
938
                        echo '<img src="' . $this->misc->icon('RaiseArgument') . '" alt="asc">';
939
                    } else {
940
                        echo '<img src="' . $this->misc->icon('LowerArgument') . '" alt="desc">';
941
                    }
942
                }
943
                echo '</a></th>' . "\n";
944
            }
945
            ++$j;
946
        }
947
948
        reset($rs->fields);
949
    }
950
951
    // Print data-row cells
952
    public function printTableRowCells(&$rs, &$fkey_information, $withOid)
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
953
    {
954
        $lang = $this->lang;
0 ignored issues
show
Unused Code introduced by
The assignment to $lang is dead and can be removed.
Loading history...
955
        $data = $this->misc->getDatabaseAccessor();
956
        $j    = 0;
957
958
        if (!isset($_REQUEST['strings'])) {
959
            $_REQUEST['strings'] = 'collapsed';
960
        }
961
962
        foreach ($rs->fields as $k => $v) {
963
            $finfo = $rs->fetchField($j++);
964
965
            if (($k === $data->id) && (!($withOid && $conf['show_oids']))) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $conf seems to be never defined.
Loading history...
966
                continue;
967
            }
968
            if (null !== $v && '' == $v) {
969
                echo '<td>&nbsp;</td>';
970
            } else {
971
                echo '<td style="white-space:nowrap;">';
972
973
                if ((null !== $v) && isset($fkey_information['byfield'][$k])) {
974
                    foreach ($fkey_information['byfield'][$k] as $conid) {
975
                        $query_params = $fkey_information['byconstr'][$conid]['url_data'];
976
977
                        foreach ($fkey_information['byconstr'][$conid]['fkeys'] as $p_field => $f_field) {
978
                            $query_params .= '&amp;' . urlencode("fkey[{$f_field}]") . '=' . urlencode($rs->fields[$p_field]);
979
                        }
980
981
                        // $fkey_information['common_url'] is already urlencoded
982
                        $query_params .= '&amp;' . $fkey_information['common_url'];
983
                        echo '<div style="display:inline-block;">';
984
                        echo '<a class="fk fk_' . htmlentities($conid, ENT_QUOTES, 'UTF-8') . "\" href=\"display.php?{$query_params}\">";
985
                        echo '<img src="' . $this->misc->icon('ForeignKey') . '" style="vertical-align:middle;" alt="[fk]" title="'
986
                        . htmlentities($fkey_information['byconstr'][$conid]['consrc'], ENT_QUOTES, 'UTF-8')
987
                            . '" />';
988
                        echo '</a>';
989
                        echo '</div>';
990
                    }
991
                    echo $this->misc->printVal($v, $finfo->type, ['null' => true, 'clip' => ('collapsed' == $_REQUEST['strings']), 'class' => 'fk_value']);
992
                } else {
993
                    echo $this->misc->printVal($v, $finfo->type, ['null' => true, 'clip' => ('collapsed' == $_REQUEST['strings'])]);
994
                }
995
                echo '</td>';
996
            }
997
        }
998
    }
999
1000
    // Print the FK row, used in ajax requests
1001
    public function doBrowseFK()
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
1002
    {
1003
        $lang = $this->lang;
1004
        $data = $this->misc->getDatabaseAccessor();
1005
1006
        $ops = [];
1007
        foreach ($_REQUEST['fkey'] as $x => $y) {
1008
            $ops[$x] = '=';
1009
        }
1010
        $query             = $data->getSelectSQL($_REQUEST['table'], [], $_REQUEST['fkey'], $ops);
1011
        $_REQUEST['query'] = $query;
1012
1013
        $fkinfo = $this->getFKInfo();
1014
1015
        $max_pages = 1;
1016
        // Retrieve page from query.  $max_pages is returned by reference.
1017
        $rs = $data->browseQuery(
1018
            'SELECT',
1019
            $_REQUEST['table'],
1020
            $_REQUEST['query'],
1021
            null,
1022
            null,
1023
            1,
1024
            1,
1025
            $max_pages
1026
        );
1027
1028
        echo '<a href="javascript:void(0);" style="display:table-cell;" class="fk_delete"><img alt="[delete]" src="' . $this->misc->icon('Delete') . '" /></a>' . "\n";
1029
        echo '<div style="display:table-cell;">';
1030
1031
        if (is_object($rs) && $rs->recordCount() > 0) {
1032
            /* we are browsing a referenced table here
1033
             * we should show OID if show_oids is true
1034
             * so we give true to withOid in functions bellow
1035
             */
1036
            echo '<table><tr>';
1037
            $this->printTableHeaderCells($rs, false, true);
1038
            echo '</tr>';
1039
            echo '<tr class="data1">' . "\n";
1040
            $this->printTableRowCells($rs, $fkinfo, true);
1041
            echo '</tr>' . "\n";
1042
            echo '</table>' . "\n";
1043
        } else {
1044
            echo $lang['strnodata'];
1045
        }
1046
        echo '</div>';
1047
    }
1048
}
1049