Passed
Push — develop ( 62dbba...8d8983 )
by Felipe
05:27
created

DisplayController::printTableRowCells()   C

Complexity

Conditions 12
Paths 10

Size

Total Lines 43
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 43
rs 5.1612
c 0
b 0
f 0
cc 12
eloc 29
nc 10
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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