Passed
Pull Request — develop (#179)
by Felipe
08:11 queued 03:02
created

DisplayController::render()   C

Complexity

Conditions 12
Paths 36

Size

Total Lines 87
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 87
rs 5.034
c 0
b 0
f 0
cc 12
eloc 61
nc 36
nop 0

How to fix   Long Method    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
        $subject = $this->coalesceArr($_REQUEST, 'subject', 'table')['subject'];
82
83
        $object = null;
84
        $object = $this->setIfIsset($object, $_REQUEST[$subject]);
85
86
        // Set the title based on the subject of the request
87
        if ('table' == $subject) {
88
            $title = $this->headerTitle('strtables', '', $object);
89
        } elseif ('view' == $subject) {
90
            $title = $this->headerTitle('strviews', '', $object);
91
        } elseif ('matview' == $subject) {
92
            $title = $this->headerTitle('strviews', 'M', $object);
93
        } elseif ('column' == $subject) {
94
            $title = $this->headerTitle('strcolumn', '', $object);
95
        } else {
96
            $title = $this->headerTitle('strqueryresults');
97
        }
98
99
        $this->printHeader($title, $scripts, true, $header_template);
100
101
        $this->printBody();
102
103
        echo $output;
104
105
        $this->printFooter(true, $footer_template);
106
    }
107
108
    /**
109
     * Displays requested data.
110
     *
111
     * @param mixed $msg
112
     */
113
    public function doBrowse($msg = '')
114
    {
115
        $conf           = $this->conf;
116
        $this->misc     = $this->misc;
117
        $plugin_manager = $this->plugin_manager;
118
        $data           = $this->misc->getDatabaseAccessor();
119
120
        // If current page is not set, default to first page
121
        $page = $this->coalesceArr($_REQUEST, 'page', 1)['page'];
122
123
        $save_history = !isset($_REQUEST['nohistory']);
124
125
        $subject = $this->coalesceArr($_REQUEST, 'subject', 'table')['subject'];
126
127
        $object = null;
128
        $object = $this->setIfIsset($object, $_REQUEST[$subject]);
129
130
        //$this->prtrace($subject, $object);
131
132
        $this->printTrail($subject);
133
134
        $this->printTabs($subject, $subject === 'database' ? 'sql' : 'browse');
135
136
        $fkey = $this->coalesceArr($_REQUEST, 'fkey')['fkey'];
137
138
        $query = $this->coalesceArr($_REQUEST, 'query')['query'];
139
        // This code is used when browsing FK in pure-xHTML (without js)
140
        if ($fkey) {
141
            $ops = [];
142
            foreach ($fkey as $x => $y) {
143
                $ops[$x] = '=';
144
            }
145
            $query             = $data->getSelectSQL($_REQUEST['table'], [], $fkey, $ops);
146
            $_REQUEST['query'] = $query;
147
        }
148
149
        if ($object && $query) {
150
            $_SESSION['sqlquery'] = $query;
151
            $this->printTitle($this->lang['strselect']);
152
            $type = 'SELECT';
153
        } elseif ($object) {
154
            $type = 'TABLE';
155
        } else {
156
            $this->printTitle($this->lang['strqueryresults']);
157
            // we come from sql, $_SESSION['sqlquery'] has been set there
158
            $type = 'QUERY';
159
        }
160
161
        $this->printMsg($msg);
162
163
        // If 'sortkey' is not set, default to ''
164
        $sortkey = $this->coalesceArr($_REQUEST, 'sortkey', '')['sortkey'];
165
166
        // If 'sortdir' is not set, default to ''
167
        $sortdir = $this->coalesceArr($_REQUEST, 'sortdir', '')['sortdir'];
168
169
        // If 'strings' is not set, default to collapsed
170
        $strings = $this->coalesceArr($_REQUEST, 'strings', 'collapsed')['strings'];
171
172
        $schema      = $this->coalesceArr($_REQUEST, 'schema')['schema'];
173
        $search_path = $this->coalesceArr($_REQUEST, 'search_path')['search_path'];
174
175
        // Fetch unique row identifier, if this is a table browse request.
176
        if ($object) {
177
            $key = $data->getRowIdentifier($object);
178
        } else {
179
            $key = [];
180
        }
181
182
        // Set the schema search path
183
        if (isset($search_path) && (0 != $data->setSearchPath(array_map('trim', explode(',', $search_path))))) {
184
            return;
185
        }
186
187
        try {
188
            // Retrieve page from query.  $max_pages is returned by reference.
189
            $resultset = $data->browseQuery(
190
                $type,
191
                $object,
192
                $query,
193
                $sortkey,
194
                $sortdir,
195
                $page,
196
                $this->conf['max_rows'],
197
                $max_pages
198
            );
199
        } catch (\PHPPgAdmin\ADOdbException $e) {
200
            return;
201
        }
202
203
        $fkey_information = $this->getFKInfo();
204
205
        // Build strings for GETs in array
206
        $_gets = [
207
            'server'   => $_REQUEST['server'],
208
            'database' => $_REQUEST['database'],
209
        ];
210
211
        $this->coalesceArr($_REQUEST, 'query');
212
        $this->coalesceArr($_REQUEST, 'count');
213
        $this->coalesceArr($_REQUEST, 'return');
214
        $this->coalesceArr($_REQUEST, 'table');
215
        $this->coalesceArr($_REQUEST, 'nohistory');
216
217
        $this->setIfIsset($_gets['schema'], $_REQUEST['schema'], null, false);
218
        $this->setIfIsset($_gets[$subject], $object, null, false);
219
        $this->setIfIsset($_gets['subject'], $subject, null, false);
220
        $this->setIfIsset($_gets['query'], $_REQUEST['query'], null, false);
221
        $this->setIfIsset($_gets['count'], $_REQUEST['count'], null, false);
222
        $this->setIfIsset($_gets['return'], $_REQUEST['return'], null, false);
223
        $this->setIfIsset($_gets['search_path'], $_REQUEST['search_path'], null, false);
224
        $this->setIfIsset($_gets['table'], $_REQUEST['table'], null, false);
225
        $this->setIfIsset($_gets['nohistory'], $_REQUEST['nohistory'], null, false);
226
        $_gets['sortkey'] = $sortkey;
227
        $_gets['sortdir'] = $sortdir;
228
        $_gets['strings'] = $strings;
229
230
        if ($save_history && is_object($resultset) && ('QUERY' == $type)) {
231
            //{
232
            $this->misc->saveScriptHistory($_REQUEST['query']);
233
        }
234
235
        $query = $query ? $query : sprintf('SELECT * FROM %s.%s', $_REQUEST['schema'], $object);
236
237
        //$query = isset($_REQUEST['query'])? $_REQUEST['query'] : "select * from {$_REQUEST['schema']}.{$_REQUEST['table']};";
238
        $this->prtrace($query);
239
        //die(htmlspecialchars($query));
240
241
        echo '<form method="post" id="sqlform" action="'.str_replace('?', '?', $_SERVER['REQUEST_URI']).'">';
242
        echo '<textarea width="90%" name="query"  id="query" rows="5" cols="100" resizable="true">';
243
244
        echo htmlspecialchars($query);
245
        echo '</textarea><br><input type="submit"/></form>';
246
247
        if (is_object($resultset) && $resultset->recordCount() > 0) {
248
            // Show page navigation
249
            $paginator = $this->_printPages($page, $max_pages, $_gets);
0 ignored issues
show
Bug introduced by
$_gets of type array is incompatible with the type string expected by parameter $gets of PHPPgAdmin\Controller\Di...ntroller::_printPages(). ( Ignorable by Annotation )

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

249
            $paginator = $this->_printPages($page, $max_pages, /** @scrutinizer ignore-type */ $_gets);
Loading history...
250
251
            echo $paginator;
252
            echo "<table id=\"data\">\n<tr>";
253
254
            // Check that the key is actually in the result set.  This can occur for select
255
            // operations where the key fields aren't part of the select.  XXX:  We should
256
            // be able to support this, somehow.
257
            foreach ($key as $v) {
258
                // If a key column is not found in the record set, then we
259
                // can't use the key.
260
                if (!array_key_exists($v, $resultset->fields)) {
261
                    $key = [];
262
263
                    break;
264
                }
265
            }
266
267
            $buttons = [
268
                'edit'   => [
269
                    'content' => $this->lang['stredit'],
270
                    'attr'    => [
271
                        'href' => [
272
                            'url'     => 'display',
273
                            'urlvars' => array_merge(
274
                                [
275
                                    'action'  => 'confeditrow',
276
                                    'strings' => $strings,
277
                                    'page'    => $page,
278
                                ],
279
                                $_gets
280
                            ),
281
                        ],
282
                    ],
283
                ],
284
                'delete' => [
285
                    'content' => $this->lang['strdelete'],
286
                    'attr'    => [
287
                        'href' => [
288
                            'url'     => 'display',
289
                            'urlvars' => array_merge(
290
                                [
291
                                    'action'  => 'confdelrow',
292
                                    'strings' => $strings,
293
                                    'page'    => $page,
294
                                ],
295
                                $_gets
296
                            ),
297
                        ],
298
                    ],
299
                ],
300
            ];
301
            $actions = [
302
                'actionbuttons' => &$buttons,
303
                'place'         => 'display-browse',
304
            ];
305
            $plugin_manager->doHook('actionbuttons', $actions);
306
307
            foreach (array_keys($actions['actionbuttons']) as $this->action) {
308
                $actions['actionbuttons'][$this->action]['attr']['href']['urlvars'] = array_merge(
309
                    $actions['actionbuttons'][$this->action]['attr']['href']['urlvars'],
310
                    $_gets
311
                );
312
            }
313
314
            $edit_params = isset($actions['actionbuttons']['edit']) ?
315
            $actions['actionbuttons']['edit'] : [];
316
            $delete_params = isset($actions['actionbuttons']['delete']) ?
317
            $actions['actionbuttons']['delete'] : [];
318
319
            // Display edit and delete actions if we have a key
320
            $colspan = count($buttons);
321
            if ($colspan > 0 and count($key) > 0) {
322
                echo "<th colspan=\"{$colspan}\" class=\"data\">{$this->lang['stractions']}</th>"."\n";
323
            }
324
325
            // we show OIDs only if we are in TABLE or SELECT type browsing
326
            $this->printTableHeaderCells($resultset, $_gets, isset($object));
327
328
            echo '</tr>'."\n";
329
330
            $i = 0;
331
            reset($resultset->fields);
332
            while (!$resultset->EOF) {
333
                $id = (0 == ($i % 2) ? '1' : '2');
334
                echo "<tr class=\"data{$id}\">"."\n";
335
                // Display edit and delete links if we have a key
336
                if ($colspan > 0 and count($key) > 0) {
337
                    $keys_array = [];
338
                    $has_nulls  = false;
339
                    foreach ($key as $v) {
340
                        if (null === $resultset->fields[$v]) {
341
                            $has_nulls = true;
342
343
                            break;
344
                        }
345
                        $keys_array["key[{$v}]"] = $resultset->fields[$v];
346
                    }
347
                    if ($has_nulls) {
348
                        echo "<td colspan=\"{$colspan}\">&nbsp;</td>"."\n";
349
                    } else {
350
                        if (isset($actions['actionbuttons']['edit'])) {
351
                            $actions['actionbuttons']['edit']                            = $edit_params;
352
                            $actions['actionbuttons']['edit']['attr']['href']['urlvars'] = array_merge(
353
                                $actions['actionbuttons']['edit']['attr']['href']['urlvars'],
354
                                $keys_array
355
                            );
356
                        }
357
358
                        if (isset($actions['actionbuttons']['delete'])) {
359
                            $actions['actionbuttons']['delete']                            = $delete_params;
360
                            $actions['actionbuttons']['delete']['attr']['href']['urlvars'] = array_merge(
361
                                $actions['actionbuttons']['delete']['attr']['href']['urlvars'],
362
                                $keys_array
363
                            );
364
                        }
365
366
                        foreach ($actions['actionbuttons'] as $this->action) {
367
                            echo "<td class=\"opbutton{$id}\">";
368
                            $this->printLink($this->action, true, __METHOD__);
369
                            echo '</td>'."\n";
370
                        }
371
                    }
372
                }
373
374
                $this->printTableRowCells($resultset, $fkey_information, isset($object));
375
376
                echo '</tr>'."\n";
377
                $resultset->moveNext();
378
                ++$i;
379
            }
380
            echo '</table>'."\n";
381
382
            echo '<p>', $resultset->recordCount(), " {$this->lang['strrows']}</p>"."\n";
383
            // Show page navigation
384
            echo $paginator;
385
        } else {
386
            echo "<p>{$this->lang['strnodata']}</p>"."\n";
387
        }
388
389
        // Navigation links
390
        $navlinks = [];
391
392
        $fields = [
393
            'server'   => $_REQUEST['server'],
394
            'database' => $_REQUEST['database'],
395
        ];
396
397
        $this->setIfIsset($fields['schema'], $_REQUEST['schema'], null, false);
398
399
        // Return
400
        if (isset($_REQUEST['return'])) {
401
            $urlvars = $this->misc->getSubjectParams($_REQUEST['return']);
402
403
            $navlinks['back'] = [
404
                'attr'    => [
405
                    'href' => [
406
                        'url'     => $urlvars['url'],
407
                        'urlvars' => $urlvars['params'],
408
                    ],
409
                ],
410
                'content' => $this->lang['strback'],
411
            ];
412
        }
413
414
        // Edit SQL link
415
        if ('QUERY' == $type) {
416
            $navlinks['edit'] = [
417
                'attr'    => [
418
                    'href' => [
419
                        'url'     => 'database',
420
                        'urlvars' => array_merge(
421
                            $fields,
422
                            [
423
                                'action'   => 'sql',
424
                                'paginate' => 'on',
425
                            ]
426
                        ),
427
                    ],
428
                ],
429
                'content' => $this->lang['streditsql'],
430
            ];
431
        }
432
433
        // Expand/Collapse
434
        if ('expanded' == $strings) {
435
            $navlinks['collapse'] = [
436
                'attr'    => [
437
                    'href' => [
438
                        'url'     => 'display',
439
                        'urlvars' => array_merge(
440
                            $_gets,
441
                            [
442
                                'strings' => 'collapsed',
443
                                'page'    => $page,
444
                            ]
445
                        ),
446
                    ],
447
                ],
448
                'content' => $this->lang['strcollapse'],
449
            ];
450
        } else {
451
            $navlinks['collapse'] = [
452
                'attr'    => [
453
                    'href' => [
454
                        'url'     => 'display',
455
                        'urlvars' => array_merge(
456
                            $_gets,
457
                            [
458
                                'strings' => 'expanded',
459
                                'page'    => $page,
460
                            ]
461
                        ),
462
                    ],
463
                ],
464
                'content' => $this->lang['strexpand'],
465
            ];
466
        }
467
468
        // Create view and download
469
        if (isset($_REQUEST['query'], $resultset) && is_object($resultset) && $resultset->recordCount() > 0) {
470
            // Report views don't set a schema, so we need to disable create view in that case
471
            if (isset($_REQUEST['schema'])) {
472
                $navlinks['createview'] = [
473
                    'attr'    => [
474
                        'href' => [
475
                            'url'     => 'views',
476
                            'urlvars' => array_merge(
477
                                $fields,
478
                                [
479
                                    'action'         => 'create',
480
                                    'formDefinition' => $_REQUEST['query'],
481
                                ]
482
                            ),
483
                        ],
484
                    ],
485
                    'content' => $this->lang['strcreateview'],
486
                ];
487
            }
488
489
            $urlvars = [];
490
491
            $this->setIfIsset($urlvars['search_path'], $_REQUEST['search_path'], null, false);
492
493
            $navlinks['download'] = [
494
                'attr'    => [
495
                    'href' => [
496
                        'url'     => 'dataexport',
497
                        'urlvars' => array_merge($fields, $urlvars),
498
                    ],
499
                ],
500
                'content' => $this->lang['strdownload'],
501
            ];
502
        }
503
504
        // Insert
505
        if (isset($object) && (isset($subject) && 'table' == $subject)) {
506
            $navlinks['insert'] = [
507
                'attr'    => [
508
                    'href' => [
509
                        'url'     => 'tables',
510
                        'urlvars' => array_merge(
511
                            $fields,
512
                            [
513
                                'action' => 'confinsertrow',
514
                                'table'  => $object,
515
                            ]
516
                        ),
517
                    ],
518
                ],
519
                'content' => $this->lang['strinsert'],
520
            ];
521
        }
522
523
        // Refresh
524
        $navlinks['refresh'] = [
525
            'attr'    => [
526
                'href' => [
527
                    'url'     => 'display',
528
                    'urlvars' => array_merge(
529
                        $_gets,
530
                        [
531
                            'strings' => $strings,
532
                            'page'    => $page,
533
                        ]
534
                    ),
535
                ],
536
            ],
537
            'content' => $this->lang['strrefresh'],
538
        ];
539
540
        $this->printNavLinks($navlinks, 'display-browse', get_defined_vars());
541
    }
542
543
    /**
544
     * Show confirmation of edit and perform actual update.
545
     *
546
     * @param mixed $confirm
547
     * @param mixed $msg
548
     */
549
    public function doEditRow($confirm, $msg = '')
550
    {
551
        $data = $this->misc->getDatabaseAccessor();
552
553
        if (is_array($_REQUEST['key'])) {
554
            $key = $_REQUEST['key'];
555
        } else {
556
            $key = unserialize(urldecode($_REQUEST['key']));
557
        }
558
559
        if ($confirm) {
560
            $this->printTrail($_REQUEST['subject']);
561
            $this->printTitle($this->lang['streditrow']);
562
            $this->printMsg($msg);
563
564
            $attrs     = $data->getTableAttributes($_REQUEST['table']);
565
            $resultset = $data->browseRow($_REQUEST['table'], $key);
566
567
            if (('disable' != $this->conf['autocomplete'])) {
568
                $fksprops = $this->misc->getAutocompleteFKProperties($_REQUEST['table']);
569
                if (false !== $fksprops) {
570
                    echo $fksprops['code'];
571
                }
572
            } else {
573
                $fksprops = false;
574
            }
575
576
            echo '<form action="'.\SUBFOLDER.'/src/views/display" method="post" id="ac_form">'."\n";
577
578
            /*echo '<p>';
579
            if (!$error) {
580
            echo "<input type=\"submit\" name=\"save\" accesskey=\"r\" value=\"{$this->lang['strsave']}\" />" . "\n";
581
            }
582
583
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$this->lang['strcancel']}\" />" . "\n";
584
585
            echo '</p>' . "\n";*/
586
587
            $elements = 0;
588
            $error    = true;
589
            if (1 == $resultset->recordCount() && $attrs->recordCount() > 0) {
590
                echo '<table>'."\n";
591
592
                // Output table header
593
                echo "<tr><th class=\"data\">{$this->lang['strcolumn']}</th><th class=\"data\">{$this->lang['strtype']}</th>";
594
                echo "<th class=\"data\">{$this->lang['strformat']}</th>"."\n";
595
                echo "<th class=\"data\">{$this->lang['strnull']}</th><th class=\"data\">{$this->lang['strvalue']}</th></tr>";
596
597
                $i = 0;
598
                while (!$attrs->EOF) {
599
                    $attrs->fields['attnotnull'] = $data->phpBool($attrs->fields['attnotnull']);
600
                    $id                          = (0 == ($i % 2) ? '1' : '2');
601
602
                    // Initialise variables
603
                    if (!isset($_REQUEST['format'][$attrs->fields['attname']])) {
604
                        $_REQUEST['format'][$attrs->fields['attname']] = 'VALUE';
605
                    }
606
607
                    echo "<tr class=\"data{$id}\">"."\n";
608
                    echo '<td style="white-space:nowrap;">', $this->misc->printVal($attrs->fields['attname']), '</td>';
609
                    echo '<td style="white-space:nowrap;">'."\n";
610
                    echo $this->misc->printVal($data->formatType($attrs->fields['type'], $attrs->fields['atttypmod']));
611
                    echo '<input type="hidden" name="types[', htmlspecialchars($attrs->fields['attname']), ']" value="',
612
                    htmlspecialchars($attrs->fields['type']), '" /></td>';
613
                    ++$elements;
614
                    echo '<td style="white-space:nowrap;">'."\n";
615
                    echo '<select name="format['.htmlspecialchars($attrs->fields['attname']), ']">'."\n";
616
                    echo '<option value="VALUE"', ($_REQUEST['format'][$attrs->fields['attname']] == 'VALUE') ? ' selected="selected"' : '', ">{$this->lang['strvalue']}</option>"."\n";
617
                    $selected = ($_REQUEST['format'][$attrs->fields['attname']] == 'EXPRESSION') ? ' selected="selected"' : '';
618
                    echo '<option value="EXPRESSION"'.$selected.">{$this->lang['strexpression']}</option>"."\n";
619
                    echo "</select>\n</td>"."\n";
620
                    ++$elements;
621
                    echo '<td style="white-space:nowrap;">';
622
                    // Output null box if the column allows nulls (doesn't look at CHECKs or ASSERTIONS)
623
                    if (!$attrs->fields['attnotnull']) {
624
                        // Set initial null values
625
                        if ('confeditrow' == $_REQUEST['action'] && null === $resultset->fields[$attrs->fields['attname']]) {
626
                            $_REQUEST['nulls'][$attrs->fields['attname']] = 'on';
627
                        }
628
                        echo "<label><span><input type=\"checkbox\" name=\"nulls[{$attrs->fields['attname']}]\"",
629
                        isset($_REQUEST['nulls'][$attrs->fields['attname']]) ? ' checked="checked"' : '', ' /></span></label></td>'."\n";
630
                        ++$elements;
631
                    } else {
632
                        echo '&nbsp;</td>';
633
                    }
634
635
                    echo "<td id=\"row_att_{$attrs->fields['attnum']}\" style=\"white-space:nowrap;\">";
636
637
                    $extras = [];
638
639
                    // If the column allows nulls, then we put a JavaScript action on the data field to unset the
640
                    // NULL checkbox as soon as anything is entered in the field.  We use the $elements variable to
641
                    // keep track of which element offset we're up to.  We can't refer to the null checkbox by name
642
                    // as it contains '[' and ']' characters.
643
                    if (!$attrs->fields['attnotnull']) {
644
                        $extras['onChange'] = 'elements['.($elements - 1).'].checked = false;';
645
                    }
646
647
                    if ((false !== $fksprops) && isset($fksprops['byfield'][$attrs->fields['attnum']])) {
648
                        $extras['id']           = "attr_{$attrs->fields['attnum']}";
649
                        $extras['autocomplete'] = 'off';
650
                    }
651
652
                    echo $data->printField("values[{$attrs->fields['attname']}]", $resultset->fields[$attrs->fields['attname']], $attrs->fields['type'], $extras);
653
654
                    echo '</td>';
655
                    ++$elements;
656
                    echo '</tr>'."\n";
657
                    ++$i;
658
                    $attrs->moveNext();
659
                }
660
                echo '</table>'."\n";
661
662
                $error = false;
663
            } elseif (1 != $resultset->recordCount()) {
664
                echo "<p>{$this->lang['strrownotunique']}</p>"."\n";
665
            } else {
666
                echo "<p>{$this->lang['strinvalidparam']}</p>"."\n";
667
            }
668
669
            echo '<input type="hidden" name="action" value="editrow" />'."\n";
670
            echo $this->misc->form;
671
            if (isset($_REQUEST['table'])) {
672
                echo '<input type="hidden" name="table" value="', htmlspecialchars($_REQUEST['table']), '" />'."\n";
673
            }
674
675
            if (isset($_REQUEST['subject'])) {
676
                echo '<input type="hidden" name="subject" value="', htmlspecialchars($_REQUEST['subject']), '" />'."\n";
677
            }
678
679
            if (isset($_REQUEST['query'])) {
680
                echo '<input type="hidden" name="query" value="', htmlspecialchars($_REQUEST['query']), '" />'."\n";
681
            }
682
683
            if (isset($_REQUEST['count'])) {
684
                echo '<input type="hidden" name="count" value="', htmlspecialchars($_REQUEST['count']), '" />'."\n";
685
            }
686
687
            if (isset($_REQUEST['return'])) {
688
                echo '<input type="hidden" name="return" value="', htmlspecialchars($_REQUEST['return']), '" />'."\n";
689
            }
690
691
            echo '<input type="hidden" name="page" value="', htmlspecialchars($_REQUEST['page']), '" />'."\n";
692
            echo '<input type="hidden" name="sortkey" value="', htmlspecialchars($_REQUEST['sortkey']), '" />'."\n";
693
            echo '<input type="hidden" name="sortdir" value="', htmlspecialchars($_REQUEST['sortdir']), '" />'."\n";
694
            echo '<input type="hidden" name="strings" value="', htmlspecialchars($_REQUEST['strings']), '" />'."\n";
695
            echo '<input type="hidden" name="key" value="', htmlspecialchars(urlencode(serialize($key))), '" />'."\n";
696
            echo '<p>';
697
            if (!$error) {
698
                echo "<input type=\"submit\" name=\"save\" accesskey=\"r\" value=\"{$this->lang['strsave']}\" />"."\n";
699
            }
700
701
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$this->lang['strcancel']}\" />"."\n";
702
703
            if (false !== $fksprops) {
704
                if ('default off' != $this->conf['autocomplete']) {
705
                    echo "<input type=\"checkbox\" id=\"no_ac\" value=\"1\" checked=\"checked\" /><label for=\"no_ac\">{$this->lang['strac']}</label>"."\n";
706
                } else {
707
                    echo "<input type=\"checkbox\" id=\"no_ac\" value=\"0\" /><label for=\"no_ac\">{$this->lang['strac']}</label>"."\n";
708
                }
709
            }
710
711
            echo '</p>'."\n";
712
            echo '</form>'."\n";
713
        } else {
714
            if (!isset($_POST['values'])) {
715
                $_POST['values'] = [];
716
            }
717
718
            if (!isset($_POST['nulls'])) {
719
                $_POST['nulls'] = [];
720
            }
721
722
            $status = $data->editRow(
723
                $_POST['table'],
724
                $_POST['values'],
725
                $_POST['nulls'],
726
                $_POST['format'],
727
                $_POST['types'],
728
                $key
729
            );
730
            if (0 == $status) {
731
                $this->doBrowse($this->lang['strrowupdated']);
732
            } elseif ($status == -2) {
733
                $this->doEditRow(true, $this->lang['strrownotunique']);
734
            } else {
735
                $this->doEditRow(true, $this->lang['strrowupdatedbad']);
736
            }
737
        }
738
    }
739
740
    /**
741
     * Show confirmation of drop and perform actual drop.
742
     *
743
     * @param mixed $confirm
744
     */
745
    public function doDelRow($confirm)
746
    {
747
        $data = $this->misc->getDatabaseAccessor();
748
749
        if ($confirm) {
750
            $this->printTrail($_REQUEST['subject']);
751
            $this->printTitle($this->lang['strdeleterow']);
752
753
            $resultset = $data->browseRow($_REQUEST['table'], $_REQUEST['key']);
754
755
            echo '<form action="'.\SUBFOLDER.'/src/views/display" method="post">'."\n";
756
            echo $this->misc->form;
757
758
            if (1 == $resultset->recordCount()) {
759
                echo "<p>{$this->lang['strconfdeleterow']}</p>"."\n";
760
761
                $fkinfo = [];
762
                echo '<table><tr>';
763
                $this->printTableHeaderCells($resultset, false, true);
764
                echo '</tr>';
765
                echo '<tr class="data1">'."\n";
766
                $this->printTableRowCells($resultset, $fkinfo, true);
767
                echo '</tr>'."\n";
768
                echo '</table>'."\n";
769
                echo '<br />'."\n";
770
771
                echo '<input type="hidden" name="action" value="delrow" />'."\n";
772
                echo "<input type=\"submit\" name=\"yes\" value=\"{$this->lang['stryes']}\" />"."\n";
773
                echo "<input type=\"submit\" name=\"no\" value=\"{$this->lang['strno']}\" />"."\n";
774
            } elseif (1 != $resultset->recordCount()) {
775
                echo "<p>{$this->lang['strrownotunique']}</p>"."\n";
776
                echo "<input type=\"submit\" name=\"cancel\" value=\"{$this->lang['strcancel']}\" />"."\n";
777
            } else {
778
                echo "<p>{$this->lang['strinvalidparam']}</p>"."\n";
779
                echo "<input type=\"submit\" name=\"cancel\" value=\"{$this->lang['strcancel']}\" />"."\n";
780
            }
781
            if (isset($_REQUEST['table'])) {
782
                echo '<input type="hidden" name="table" value="', htmlspecialchars($_REQUEST['table']), '" />'."\n";
783
            }
784
785
            if (isset($_REQUEST['subject'])) {
786
                echo '<input type="hidden" name="subject" value="', htmlspecialchars($_REQUEST['subject']), '" />'."\n";
787
            }
788
789
            if (isset($_REQUEST['query'])) {
790
                echo '<input type="hidden" name="query" value="', htmlspecialchars($_REQUEST['query']), '" />'."\n";
791
            }
792
793
            if (isset($_REQUEST['count'])) {
794
                echo '<input type="hidden" name="count" value="', htmlspecialchars($_REQUEST['count']), '" />'."\n";
795
            }
796
797
            if (isset($_REQUEST['return'])) {
798
                echo '<input type="hidden" name="return" value="', htmlspecialchars($_REQUEST['return']), '" />'."\n";
799
            }
800
801
            echo '<input type="hidden" name="page" value="', htmlspecialchars($_REQUEST['page']), '" />'."\n";
802
            echo '<input type="hidden" name="sortkey" value="', htmlspecialchars($_REQUEST['sortkey']), '" />'."\n";
803
            echo '<input type="hidden" name="sortdir" value="', htmlspecialchars($_REQUEST['sortdir']), '" />'."\n";
804
            echo '<input type="hidden" name="strings" value="', htmlspecialchars($_REQUEST['strings']), '" />'."\n";
805
            echo '<input type="hidden" name="key" value="', htmlspecialchars(urlencode(serialize($_REQUEST['key']))), '" />'."\n";
806
            echo '</form>'."\n";
807
        } else {
808
            $status = $data->deleteRow($_POST['table'], unserialize(urldecode($_POST['key'])));
809
            if (0 == $status) {
810
                $this->doBrowse($this->lang['strrowdeleted']);
811
            } elseif ($status == -2) {
812
                $this->doBrowse($this->lang['strrownotunique']);
813
            } else {
814
                $this->doBrowse($this->lang['strrowdeletedbad']);
815
            }
816
        }
817
    }
818
819
    /**
820
     * Build & return the FK information data structure
821
     * used when deciding if a field should have a FK link or not.
822
     *
823
     * @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...
824
     */
825
    public function &getFKInfo()
826
    {
827
        $data = $this->misc->getDatabaseAccessor();
828
829
        // Get the foreign key(s) information from the current table
830
        $fkey_information = ['byconstr' => [], 'byfield' => []];
831
832
        if (isset($_REQUEST['table'])) {
833
            $constraints = $data->getConstraintsWithFields($_REQUEST['table']);
834
            if ($constraints->recordCount() > 0) {
835
                $fkey_information['common_url'] = $this->misc->getHREF('schema').'&amp;subject=table';
836
837
                // build the FK constraints data structure
838
                while (!$constraints->EOF) {
839
                    $constr = &$constraints->fields;
840
                    if ('f' == $constr['contype']) {
841
                        if (!isset($fkey_information['byconstr'][$constr['conid']])) {
842
                            $fkey_information['byconstr'][$constr['conid']] = [
843
                                'url_data' => 'table='.urlencode($constr['f_table']).'&amp;schema='.urlencode($constr['f_schema']),
844
                                'fkeys'    => [],
845
                                'consrc'   => $constr['consrc'],
846
                            ];
847
                        }
848
849
                        $fkey_information['byconstr'][$constr['conid']]['fkeys'][$constr['p_field']] = $constr['f_field'];
850
851
                        if (!isset($fkey_information['byfield'][$constr['p_field']])) {
852
                            $fkey_information['byfield'][$constr['p_field']] = [];
853
                        }
854
855
                        $fkey_information['byfield'][$constr['p_field']][] = $constr['conid'];
856
                    }
857
                    $constraints->moveNext();
858
                }
859
            }
860
        }
861
862
        return $fkey_information;
863
    }
864
865
    /**
866
     * Print table header cells.
867
     *
868
     * @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...
869
     * @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...
870
     */
871
    public function printTableHeaderCells(&$resultset, $args, $withOid)
872
    {
873
        $data = $this->misc->getDatabaseAccessor();
874
        $j    = 0;
875
876
        foreach ($resultset->fields as $k => $v) {
877
            if (($k === $data->id) && (!($withOid && $this->conf['show_oids']))) {
878
                ++$j;
879
880
                continue;
881
            }
882
            $finfo = $resultset->fetchField($j);
883
884
            if (false === $args) {
885
                echo '<th class="data">', $this->misc->printVal($finfo->name), '</th>'."\n";
886
            } else {
887
                $args['page']    = $_REQUEST['page'];
888
                $args['sortkey'] = $j + 1;
889
                // Sort direction opposite to current direction, unless it's currently ''
890
                $args['sortdir'] = (
891
                    'asc' == $_REQUEST['sortdir']
892
                    and $_REQUEST['sortkey'] == ($j + 1)
893
                ) ? 'desc' : 'asc';
894
895
                $sortLink = http_build_query($args);
896
897
                echo "<th class=\"data\"><a href=\"?{$sortLink}\">"
898
                , $this->misc->printVal($finfo->name);
899
                if ($_REQUEST['sortkey'] == ($j + 1)) {
900
                    if ('asc' == $_REQUEST['sortdir']) {
901
                        echo '<img src="'.$this->misc->icon('RaiseArgument').'" alt="asc">';
902
                    } else {
903
                        echo '<img src="'.$this->misc->icon('LowerArgument').'" alt="desc">';
904
                    }
905
                }
906
                echo '</a></th>'."\n";
907
            }
908
            ++$j;
909
        }
910
911
        reset($resultset->fields);
912
    }
913
914
    // Print data-row cells
915
    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...
916
    {
917
        $data = $this->misc->getDatabaseAccessor();
918
        $j    = 0;
919
920
        if (!isset($_REQUEST['strings'])) {
921
            $_REQUEST['strings'] = 'collapsed';
922
        }
923
924
        foreach ($resultset->fields as $k => $v) {
925
            $finfo = $resultset->fetchField($j++);
926
927
            if (($k === $data->id) && (!($withOid && $this->conf['show_oids']))) {
928
                continue;
929
            }
930
            if (null !== $v && '' == $v) {
931
                echo '<td>&nbsp;</td>';
932
            } else {
933
                echo '<td style="white-space:nowrap;">';
934
935
                if ((null !== $v) && isset($fkey_information['byfield'][$k])) {
936
                    foreach ($fkey_information['byfield'][$k] as $conid) {
937
                        $query_params = $fkey_information['byconstr'][$conid]['url_data'];
938
939
                        foreach ($fkey_information['byconstr'][$conid]['fkeys'] as $p_field => $f_field) {
940
                            $query_params .= '&amp;'.urlencode("fkey[{$f_field}]").'='.urlencode($resultset->fields[$p_field]);
941
                        }
942
943
                        // $fkey_information['common_url'] is already urlencoded
944
                        $query_params .= '&amp;'.$fkey_information['common_url'];
945
                        echo '<div style="display:inline-block;">';
946
                        echo '<a class="fk fk_'.htmlentities($conid, ENT_QUOTES, 'UTF-8')."\" href=\"display?{$query_params}\">";
947
                        echo '<img src="'.$this->misc->icon('ForeignKey').'" style="vertical-align:middle;" alt="[fk]" title="'
948
                        .htmlentities($fkey_information['byconstr'][$conid]['consrc'], ENT_QUOTES, 'UTF-8')
949
                            .'" />';
950
                        echo '</a>';
951
                        echo '</div>';
952
                    }
953
                    echo $this->misc->printVal($v, $finfo->type, ['null' => true, 'clip' => ('collapsed' == $_REQUEST['strings']), 'class' => 'fk_value']);
954
                } else {
955
                    echo $this->misc->printVal($v, $finfo->type, ['null' => true, 'clip' => ('collapsed' == $_REQUEST['strings'])]);
956
                }
957
                echo '</td>';
958
            }
959
        }
960
    }
961
962
    // Print the FK row, used in ajax requests
963
    public function doBrowseFK()
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
964
    {
965
        $data = $this->misc->getDatabaseAccessor();
966
967
        $ops = [];
968
        foreach ($_REQUEST['fkey'] as $x => $y) {
969
            $ops[$x] = '=';
970
        }
971
        $query             = $data->getSelectSQL($_REQUEST['table'], [], $_REQUEST['fkey'], $ops);
972
        $_REQUEST['query'] = $query;
973
974
        $fkinfo = $this->getFKInfo();
975
976
        $max_pages = 1;
977
        // Retrieve page from query.  $max_pages is returned by reference.
978
        $resultset = $data->browseQuery(
979
            'SELECT',
980
            $_REQUEST['table'],
981
            $_REQUEST['query'],
982
            null,
983
            null,
984
            1,
985
            1,
986
            $max_pages
987
        );
988
989
        echo '<a href="javascript:void(0);" style="display:table-cell;" class="fk_delete"><img alt="[delete]" src="'.$this->misc->icon('Delete').'" /></a>'."\n";
990
        echo '<div style="display:table-cell;">';
991
992
        if (is_object($resultset) && $resultset->recordCount() > 0) {
993
            /* we are browsing a referenced table here
994
             * we should show OID if show_oids is true
995
             * so we give true to withOid in functions bellow
996
             */
997
            echo '<table><tr>';
998
            $this->printTableHeaderCells($resultset, false, true);
999
            echo '</tr>';
1000
            echo '<tr class="data1">'."\n";
1001
            $this->printTableRowCells($resultset, $fkinfo, true);
1002
            echo '</tr>'."\n";
1003
            echo '</table>'."\n";
1004
        } else {
1005
            echo $this->lang['strnodata'];
1006
        }
1007
        echo '</div>';
1008
    }
1009
1010
    private function _getMinMaxPages($page, $pages)
1011
    {
1012
        $window = 10;
1013
        if ($page <= $window) {
1014
            $min_page = 1;
1015
            $max_page = min(2 * $window, $pages);
1016
        } elseif ($page > $window && $pages >= $page + $window) {
1017
            $min_page = ($page - $window) + 1;
1018
            $max_page = $page + $window;
1019
        } else {
1020
            $min_page = ($page - (2 * $window - ($pages - $page))) + 1;
1021
            $max_page = $pages;
1022
        }
1023
1024
        // Make sure min_page is always at least 1
1025
        // and max_page is never greater than $pages
1026
        $min_page = max($min_page, 1);
1027
        $max_page = min($max_page, $pages);
1028
1029
        return [$min_page, $max_page];
1030
    }
1031
1032
    /**
1033
     * Do multi-page navigation.  Displays the prev, next and page options.
1034
     *
1035
     * @param int    $page      - the page currently viewed
1036
     * @param int    $pages     - the maximum number of pages
1037
     * @param string $gets      -  the parameters to include in the link to the wanted page
1038
     * @param int    $max_width - the number of pages to make available at any one time (default = 20)
1039
     *
1040
     * @return string the pagination links
1041
     */
1042
    private function _printPages($page, $pages, $gets, $max_width = 20)
1043
    {
1044
        $lang = $this->lang;
1045
        $page = (int) $page;
1046
1047
        if ($page < 0 || $page > $pages || $pages <= 1 || $max_width <= 0) {
1048
            return;
1049
        }
1050
1051
        unset($gets['page']);
1052
        $url = http_build_query($gets);
1053
1054
        $result = '<p style="text-align: center">'."\n";
1055
        if ($page != 1) {
1056
            $result .= sprintf('<a class="pagenav" href="?%s&page=1">%s</a>%s&nbsp;', $url, $lang['strfirst'], "\n");
1057
            $result .= sprintf('<a class="pagenav" href="?%s&page=%s">%s</a>%s', $url, $page - 1, $lang['strprev'], "\n");
1058
        }
1059
1060
        list($min_page, $max_page) = $this->_getMinMaxPages($page, $pages);
1061
1062
        for ($i = $min_page; $i <= $max_page; ++$i) {
1063
            $result .= (($i === $page) ? $i : sprintf('<a class="pagenav" href="display?%s&page=%s">%s</a>', $url, $i, $i))."\n";
1064
        }
1065
1066
        if ($page != $pages) {
1067
            $result .= sprintf('<a class="pagenav" href="?%s&page=%s">%s</a>%s', $url, $page + 1, $lang['strnext'], "\n");
1068
            $result .= sprintf('&nbsp;<a class="pagenav" href="?%s&page=%s">%s</a>%s', $url, $pages, $lang['strlast'], "\n");
1069
        }
1070
        $result .= "</p>\n";
1071
1072
        return $result;
1073
    }
1074
}
1075