FunctionsController::_printNavLinks()   B
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 102
Code Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 72
dl 0
loc 102
c 0
b 0
f 0
rs 8.6109
cc 3
nc 3
nop 2

How to fix   Long Method   

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 6.1.3
5
 */
6
7
namespace PHPPgAdmin\Controller;
8
9
use PHPPgAdmin\Decorators\Decorator;
10
11
/**
12
 * Base controller class.
13
 */
14
class FunctionsController extends BaseController
15
{
16
    public $table_place = 'functions-functions';
17
18
    public $controller_title = 'strfunctions';
19
20
    /**
21
     * Default method to render the controller according to the action parameter.
22
     */
23
    public function render()
24
    {
25
        if ('tree' === $this->action) {
26
            return $this->doTree();
27
        }
28
29
        $header_template = 'header_datatables.twig';
30
        $footer_template = 'footer.twig';
31
        \ob_start();
32
33
        switch ($this->action) {
34
            case 'save_create':
35
                if (null !== $this->getPostParam('cancel')) {
36
                    $this->doDefault();
37
                } else {
38
                    $this->doSaveCreate();
39
                }
40
41
                break;
42
            case 'create':
43
                $header_template = 'header_select2.twig';
44
                $this->doCreate();
45
46
                break;
47
            case 'drop':
48
                if (null !== $this->getPostParam('drop')) {
49
                    $this->doDrop(false);
50
                } else {
51
                    $this->doDefault();
52
                }
53
54
                break;
55
            case 'confirm_drop':
56
                $this->doDrop(true);
57
58
                break;
59
            case 'save_edit':
60
                if (null !== $this->getPostParam('cancel')) {
61
                    $this->doDefault();
62
                } else {
63
                    $this->doSaveEdit();
64
                }
65
66
                break;
67
            case 'edit':
68
                $header_template = 'header_sqledit.twig';
69
                $footer_template = 'footer_sqledit.twig';
70
                $this->doEdit();
71
72
                break;
73
            case 'properties':
74
                $header_template = 'header_highlight.twig';
75
                $this->doProperties();
76
77
                break;
78
            case 'show':
79
                if (isset($_GET['function'], $_GET['function_oid'])) {
80
                    $header_template = 'header_highlight.twig';
81
                    $this->showDefinition();
0 ignored issues
show
Bug introduced by
The call to PHPPgAdmin\Controller\Fu...oller::showDefinition() has too few arguments starting with fname. ( Ignorable by Annotation )

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

81
                    $this->/** @scrutinizer ignore-call */ 
82
                           showDefinition();

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
82
                } else {
83
                    $this->doDefault();
84
                }
85
86
                break;
87
88
            default:
89
                $this->doDefault();
90
91
                break;
92
        }
93
        $output = \ob_get_clean();
94
95
        $this->printHeader($this->headerTitle(), null, true, $header_template);
96
        $this->printBody();
97
        echo $output;
98
        $this->printFooter(true, $footer_template);
99
    }
100
101
    /**
102
     * Show default list of functions in the database.
103
     *
104
     * @param mixed $msg
105
     */
106
    public function doDefault($msg = ''): void
107
    {
108
        $data = $this->misc->getDatabaseAccessor();
109
110
        $this->printTrail('schema');
111
        $this->printTabs('schema', 'functions');
112
        $this->printMsg($msg);
113
114
        $funcs = $data->getFunctions();
115
116
        $columns = [
117
            'function' => [
118
                'title' => $this->lang['strfunction'],
119
                'field' => Decorator::field('proproto'),
120
                'url' => \containerInstance()->subFolder . "/redirect/function?action=properties&amp;{$this->misc->href}&amp;",
121
                'vars' => ['function' => 'proproto', 'function_oid' => 'prooid'],
122
            ],
123
            'returns' => [
124
                'title' => $this->lang['strreturns'],
125
                'field' => Decorator::field('proreturns'),
126
            ],
127
            'owner' => [
128
                'title' => $this->lang['strowner'],
129
                'field' => Decorator::field('proowner'),
130
            ],
131
            'proglanguage' => [
132
                'title' => $this->lang['strproglanguage'],
133
                'field' => Decorator::field('prolanguage'),
134
            ],
135
            'actions' => [
136
                'title' => $this->lang['stractions'],
137
            ],
138
            'comment' => [
139
                'title' => $this->lang['strcomment'],
140
                'field' => Decorator::field('procomment'),
141
            ],
142
        ];
143
144
        $actions = [
145
            'multiactions' => [
146
                'keycols' => ['function' => 'proproto', 'function_oid' => 'prooid'],
147
                'url' => 'functions',
148
            ],
149
            'alter' => [
150
                'content' => $this->lang['stralter'],
151
                'attr' => [
152
                    'href' => [
153
                        'url' => 'functions',
154
                        'urlvars' => [
155
                            'action' => 'edit',
156
                            'function' => Decorator::field('proproto'),
157
                            'function_oid' => Decorator::field('prooid'),
158
                        ],
159
                    ],
160
                ],
161
            ],
162
            'drop' => [
163
                'multiaction' => 'confirm_drop',
164
                'content' => $this->lang['strdrop'],
165
                'attr' => [
166
                    'href' => [
167
                        'url' => 'functions',
168
                        'urlvars' => [
169
                            'action' => 'confirm_drop',
170
                            'function' => Decorator::field('proproto'),
171
                            'function_oid' => Decorator::field('prooid'),
172
                        ],
173
                    ],
174
                ],
175
            ],
176
            'privileges' => [
177
                'content' => $this->lang['strprivileges'],
178
                'attr' => [
179
                    'href' => [
180
                        'url' => 'privileges',
181
                        'urlvars' => [
182
                            'subject' => 'function',
183
                            'function' => Decorator::field('proproto'),
184
                            'function_oid' => Decorator::field('prooid'),
185
                        ],
186
                    ],
187
                ],
188
            ],
189
        ];
190
191
        echo $this->printTable($funcs, $columns, $actions, $this->table_place, $this->lang['strnofunctions']);
192
193
        $this->_printNavLinks('functions-functions');
194
    }
195
196
    /**
197
     * Generate XML for the browser tree.
198
     */
199
    public function doTree()
200
    {
201
        $data = $this->misc->getDatabaseAccessor();
202
203
        $funcs = $data->getFunctions();
204
205
        $proto = Decorator::concat(Decorator::field('proname'), ' (', Decorator::field('proarguments'), ')');
206
207
        $reqvars = $this->misc->getRequestVars('function');
208
209
        $attrs = [
210
            'text' => $proto,
211
            'icon' => 'Function',
212
            'toolTip' => Decorator::field('procomment'),
213
            'action' => Decorator::redirecturl(
214
                'redirect',
215
                $reqvars,
216
                [
217
                    'action' => 'properties',
218
                    'function' => $proto,
219
                    'function_oid' => Decorator::field('prooid'),
220
                ]
221
            ),
222
        ];
223
224
        return $this->printTree($funcs, $attrs, 'functions');
0 ignored issues
show
Bug introduced by
It seems like $funcs can also be of type integer; however, parameter $_treedata of PHPPgAdmin\Controller\BaseController::printTree() does only seem to accept PHPPgAdmin\ADORecordSet|PHPPgAdmin\ArrayRecordSet, maybe add an additional type check? ( Ignorable by Annotation )

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

224
        return $this->printTree(/** @scrutinizer ignore-type */ $funcs, $attrs, 'functions');
Loading history...
225
    }
226
227
    /**
228
     * Function to save after editing a function.
229
     */
230
    public function doSaveEdit(): void
231
    {
232
        $data = $this->misc->getDatabaseAccessor();
233
234
        $fnlang = \mb_strtolower($_POST['original_lang']);
235
236
        if ('c' === $fnlang) {
237
            $def = [$_POST['formObjectFile'], $_POST['formLinkSymbol']];
238
        } elseif ('internal' === $fnlang) {
239
            $def = $_POST['formLinkSymbol'];
240
        } else {
241
            $def = $_POST['formDefinition'];
242
        }
243
244
        if (!$data->hasFunctionAlterSchema()) {
245
            $_POST['formFuncSchema'] = '';
246
        }
247
248
        $status = $data->setFunction(
249
            $_POST['original_function'],
250
            $_POST['formFunction'],
251
            $_POST['original_arguments'],
252
            $_POST['original_returns'],
253
            $def,
254
            $_POST['original_lang'],
255
            $_POST['formProperties'],
256
            isset($_POST['original_setof']),
257
            $_POST['original_owner'],
258
            $_POST['formFuncOwn'],
259
            $_POST['original_schema'],
260
            $_POST['formFuncSchema'],
261
            $_POST['formCost'] ?? null,
262
            $_POST['formRows'] ?? 0,
263
            $_POST['formComment']
264
        );
265
266
        if (0 === $status) {
267
            // If function has had schema altered, need to change to the new schema
268
            // and reload the browser frame.
269
            if (!empty($_POST['formFuncSchema']) && ($_POST['formFuncSchema'] !== $_POST['original_schema'])) {
270
                // Jump them to the new function schema
271
                $this->misc->setCurrentSchema($_POST['formFuncSchema']);
272
                // Force a browser reload
273
                $this->view->setReloadBrowser(true);
274
            }
275
            $this->doProperties($this->lang['strfunctionupdated']);
276
        } else {
277
            $this->doEdit($this->lang['strfunctionupdatedbad']);
278
        }
279
    }
280
281
    /**
282
     * Function to allow editing of a Function.
283
     *
284
     * @param mixed $msg
285
     */
286
    public function doEdit($msg = ''): void
287
    {
288
        $data = $this->misc->getDatabaseAccessor();
289
290
        $this->printTrail('function');
291
        $this->printTabs('function', 'definition');
292
        $this->printTitle($this->lang['stralter'], 'pg.function.alter');
293
        $this->printMsg($msg);
294
295
        $fndata = $data->getFunction($_REQUEST['function_oid']);
296
297
        if (0 >= $fndata->recordCount()) {
298
            echo "<p>{$this->lang['strnodata']}</p>" . \PHP_EOL;
299
300
            return;
301
        }
302
        $fndata->fields['proretset'] = $data->phpBool($fndata->fields['proretset']);
303
304
        // Initialise variables
305
        $_POST['formDefinition'] = $this->getPostParam('formDefinition', $fndata->fields['prosrc']);
306
307
        $_POST['formProperties'] = $this->getPostParam('formProperties', $data->getFunctionProperties($fndata->fields));
308
309
        $_POST['formFunction'] = $this->getPostParam('formFunction', $fndata->fields['proname']);
310
311
        $_POST['formComment'] = $this->getPostParam('formComment', $fndata->fields['procomment']);
312
313
        $_POST['formObjectFile'] = $this->getPostParam('formObjectFile', $fndata->fields['probin']);
314
315
        $_POST['formLinkSymbol'] = $this->getPostParam('formLinkSymbol', $fndata->fields['prosrc']);
316
317
        $_POST['formFuncOwn'] = $this->getPostParam('formFuncOwn', $fndata->fields['proowner']);
318
319
        $_POST['formFuncSchema'] = $this->getPostParam('formFuncSchema', $fndata->fields['proschema']);
320
321
        if ($data->hasFunctionCosting()) {
322
            $_POST['formCost'] = $this->getPostParam('formCost', $fndata->fields['procost']);
323
324
            $_POST['formRows'] = $this->getPostParam('formRows', $fndata->fields['prorows']);
325
        }
326
327
        // Deal with named parameters
328
        if ($data->hasNamedParams()) {
329
            $args = $this->_getNamedParamsArgs($data, $fndata);
330
        } else {
331
            $args = $fndata->fields['proarguments'];
332
        }
333
334
        echo '<form action="' . \containerInstance()->subFolder . '/src/views/functions" method="post">' . \PHP_EOL;
335
        echo '<table style="width: 95%">' . \PHP_EOL;
336
        echo '<tr>' . \PHP_EOL;
337
        echo "<th class=\"data required\">{$this->lang['strschema']}</th>" . \PHP_EOL;
338
        echo "<th class=\"data required\">{$this->lang['strfunction']}</th>" . \PHP_EOL;
339
        echo "<th class=\"data\">{$this->lang['strarguments']}</th>" . \PHP_EOL;
340
        echo "<th class=\"data required\">{$this->lang['strreturns']}</th>" . \PHP_EOL;
341
        echo "<th class=\"data required\">{$this->lang['strproglanguage']}</th>" . \PHP_EOL;
342
        echo '</tr>' . \PHP_EOL;
343
344
        echo '<tr>' . \PHP_EOL;
345
        echo '<td class="data1">';
346
        echo '<input type="hidden" name="original_schema" value="', \htmlspecialchars($fndata->fields['proschema']), '" />' . \PHP_EOL;
347
348
        if ($data->hasFunctionAlterSchema()) {
349
            $schemas = $data->getSchemas();
350
            echo '<select name="formFuncSchema">';
351
352
            while (!$schemas->EOF) {
353
                $schema = $schemas->fields['nspname'];
354
                echo '<option value="', \htmlspecialchars($schema), '"',
355
                ($schema === $_POST['formFuncSchema']) ? ' selected="selected"' : '', '>', \htmlspecialchars($schema), '</option>' . \PHP_EOL;
356
                $schemas->moveNext();
357
            }
358
            echo '</select>' . \PHP_EOL;
359
        } else {
360
            echo $fndata->fields['proschema'];
361
        }
362
363
        echo '</td>' . \PHP_EOL;
364
        echo '<td class="data1">';
365
        echo '<input type="hidden" name="original_function" value="', \htmlspecialchars($fndata->fields['proname']), '" />' . \PHP_EOL;
366
        echo "<input name=\"formFunction\" style=\"width: 100%; box-sizing: border-box;\" maxlength=\"{$data->_maxNameLen}\" value=\"", \htmlspecialchars($_POST['formFunction']), '" />';
367
        echo '</td>' . \PHP_EOL;
368
369
        echo '<td class="data1">', $this->misc->printVal($args), \PHP_EOL;
370
        echo '<input type="hidden" name="original_arguments" value="', \htmlspecialchars($args), '" />' . \PHP_EOL;
371
        echo '</td>' . \PHP_EOL;
372
373
        echo '<td class="data1">';
374
375
        if ($fndata->fields['proretset']) {
376
            echo 'setof ';
377
        }
378
379
        echo $this->misc->printVal($fndata->fields['proresult']), \PHP_EOL;
380
        echo '<input type="hidden" name="original_returns" value="', \htmlspecialchars($fndata->fields['proresult']), '" />' . \PHP_EOL;
381
382
        if ($fndata->fields['proretset']) {
383
            echo '<input type="hidden" name="original_setof" value="yes" />' . \PHP_EOL;
384
        }
385
386
        echo '</td>' . \PHP_EOL;
387
388
        echo '<td class="data1">', $this->misc->printVal($fndata->fields['prolanguage']), \PHP_EOL;
389
        echo '<input type="hidden" name="original_lang" value="', \htmlspecialchars($fndata->fields['prolanguage']), '" />' . \PHP_EOL;
390
        echo '</td>' . \PHP_EOL;
391
        echo '</tr>' . \PHP_EOL;
392
393
        $fnlang = \mb_strtolower($fndata->fields['prolanguage']);
394
395
        if ('c' === $fnlang) {
396
            echo "<tr><th class=\"data required\" colspan=\"2\">{$this->lang['strobjectfile']}</th>" . \PHP_EOL;
397
            echo "<th class=\"data\" colspan=\"2\">{$this->lang['strlinksymbol']}</th></tr>" . \PHP_EOL;
398
            echo '<tr><td class="data1" colspan="2"><input type="text" name="formObjectFile" style="width:100%" value="',
399
            \htmlspecialchars($_POST['formObjectFile']), '" /></td>' . \PHP_EOL;
400
            echo '<td class="data1" colspan="2"><input type="text" name="formLinkSymbol" style="width:100%" value="',
401
            \htmlspecialchars($_POST['formLinkSymbol']), '" /></td></tr>' . \PHP_EOL;
402
        } elseif ('internal' === $fnlang) {
403
            echo "<tr><th class=\"data\" colspan=\"5\">{$this->lang['strlinksymbol']}</th></tr>" . \PHP_EOL;
404
            echo '<tr><td class="data1" colspan="5"><input type="text" name="formLinkSymbol" style="width:100%" value="',
405
            \htmlspecialchars($_POST['formLinkSymbol']), '" /></td></tr>' . \PHP_EOL;
406
        } else {
407
            echo "<tr><th class=\"data required\" colspan=\"5\">{$this->lang['strdefinition']}</th></tr>" . \PHP_EOL;
408
            echo '<tr><td class="data1" colspan="5">';
409
            $textarea_id = ('sql' === $fnlang || 'plpgsql' === $fnlang) ? 'query' : 'formDefinition';
410
            echo '<textarea style="width:100%;" rows="20" cols="50" id="' . $textarea_id . '" name="formDefinition">';
411
            echo \htmlspecialchars($_POST['formDefinition']);
412
            echo '</textarea></td></tr>' . \PHP_EOL;
413
        }
414
415
        // Display function comment
416
        echo "<tr><th class=\"data\" colspan=\"5\">{$this->lang['strcomment']}</th></tr>" . \PHP_EOL;
417
        echo '<tr><td class="data1" colspan="5">';
418
        echo '<textarea style="width:100%;" name="formComment" rows="3" cols="50">';
419
        echo \htmlspecialchars($_POST['formComment']);
420
        echo '</textarea></td></tr>' . \PHP_EOL;
421
422
        // Display function cost options
423
        if ($data->hasFunctionCosting()) {
424
            echo "<tr><th class=\"data required\" colspan=\"5\">{$this->lang['strfunctioncosting']}</th></tr>" . \PHP_EOL;
425
            echo "<td class=\"data1\" colspan=\"2\">{$this->lang['strexecutioncost']}: <input name=\"formCost\" size=\"16\" value=\"" .
426
            \htmlspecialchars($_POST['formCost']) . '" /></td>';
427
            echo "<td class=\"data1\" colspan=\"2\">{$this->lang['strresultrows']}: <input name=\"formRows\" size=\"16\" value=\"",
428
            \htmlspecialchars($_POST['formRows']), '"', (!$fndata->fields['proretset']) ? 'disabled' : '', '/></td>';
429
        }
430
431
        // Display function properties
432
        if (\is_array($data->funcprops) && 0 < \count($data->funcprops)) {
433
            echo "<tr><th class=\"data\" colspan=\"5\">{$this->lang['strproperties']}</th></tr>" . \PHP_EOL;
434
            echo '<tr><td class="data1" colspan="5">' . \PHP_EOL;
435
            $i = 0;
436
437
            foreach ($data->funcprops as $k => $v) {
438
                echo "<select name=\"formProperties[{$i}]\">" . \PHP_EOL;
439
440
                foreach ($v as $p) {
441
                    echo '<option value="', \htmlspecialchars($p), '"',
442
                    ($_POST['formProperties'][$i] === $p) ? ' selected="selected"' : '',
443
                    '>', $this->misc->printVal($p), '</option>' . \PHP_EOL;
444
                }
445
                echo '</select><br />' . \PHP_EOL;
446
                ++$i;
447
            }
448
            echo '</td></tr>' . \PHP_EOL;
449
        }
450
451
        // function owner
452
        if ($data->hasFunctionAlterOwner()) {
453
            $users = $data->getUsers();
454
            echo "<tr><td class=\"data1\" colspan=\"5\">{$this->lang['strowner']}: <select name=\"formFuncOwn\">";
455
456
            while (!$users->EOF) {
457
                $uname = $users->fields['usename'];
458
                echo '<option value="', \htmlspecialchars($uname), '"',
459
                ($uname === $_POST['formFuncOwn']) ? ' selected="selected"' : '', '>', \htmlspecialchars($uname), '</option>' . \PHP_EOL;
460
                $users->moveNext();
461
            }
462
            echo '</select>' . \PHP_EOL;
463
            echo '<input type="hidden" name="original_owner" value="', \htmlspecialchars($fndata->fields['proowner']), '" />' . \PHP_EOL;
464
            echo '</td></tr>' . \PHP_EOL;
465
        }
466
        echo '</table>' . \PHP_EOL;
467
        echo '<p><input type="hidden" name="action" value="save_edit" />' . \PHP_EOL;
468
        echo '<input type="hidden" name="function" value="', \htmlspecialchars($_REQUEST['function']), '" />' . \PHP_EOL;
469
        echo '<input type="hidden" name="function_oid" value="', \htmlspecialchars($_REQUEST['function_oid']), '" />' . \PHP_EOL;
470
        echo $this->view->form;
471
        echo "<input type=\"submit\" value=\"{$this->lang['stralter']}\" />" . \PHP_EOL;
472
        echo \sprintf('<input type="submit" name="cancel" value="%s"  /></p>%s', $this->lang['strcancel'], \PHP_EOL);
473
        echo '</form>' . \PHP_EOL;
474
    }
475
476
    /**
477
     * Show the creation sentence for this function.
478
     *
479
     * @param string $fname        The function name
480
     * @param int    $function_oid The function oid
481
     *
482
     * @return string the navlinks to print at the bottom
483
     */
484
    public function showDefinition($fname, $function_oid)
0 ignored issues
show
Unused Code introduced by
The parameter $fname is not used and could be removed. ( Ignorable by Annotation )

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

484
    public function showDefinition(/** @scrutinizer ignore-unused */ $fname, $function_oid)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
485
    {
486
        $data = $this->misc->getDatabaseAccessor();
487
488
        $this->printTrail('function');
489
        $this->printTabs('function', 'export');
490
        $this->printTitle($this->lang['strproperties'], 'pg.function');
491
492
        $fname = \str_replace(' ', '', $f);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $f seems to be never defined.
Loading history...
493
        $funcdata = $data->getFunctionDef($function_oid);
494
        $func_full = '';
495
496
        if (0 >= $funcdata->recordCount()) {
497
            echo "<p>{$this->lang['strnodata']}</p>" . \PHP_EOL;
498
499
            return $this->_printNavLinks('functions-properties', $func_full);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_printNavL...roperties', $func_full) returns the type void which is incompatible with the documented return type string.
Loading history...
500
        }
501
502
        echo '<table style="width: 95%">' . \PHP_EOL;
503
504
        $fnlang = \mb_strtolower($funcdata->fields['prolanguage']);
0 ignored issues
show
Unused Code introduced by
The assignment to $fnlang is dead and can be removed.
Loading history...
505
        echo '<tr><td class="data1" colspan="4">';
506
        echo \sprintf('<pre><code class="sql hljs">%s', \PHP_EOL);
507
508
        echo \sprintf('%s--%s', \PHP_EOL, \PHP_EOL);
509
        echo \sprintf('-- Name: %s; Type: FUNCTION; Schema: %s; Owner: %s', $fname, $funcdata->fields['nspname'], $funcdata->fields['relowner']);
510
        echo \sprintf('%s--%s%s', \PHP_EOL, \PHP_EOL, \PHP_EOL);
511
512
        echo \sprintf('%s;', $funcdata->fields['pg_get_functiondef']);
513
514
        echo \sprintf('%s%sALTER FUNCTION %s OWNER TO %s;%s', \PHP_EOL, \PHP_EOL, $fname, $funcdata->fields['relowner'], \PHP_EOL);
515
516
        // Show comment if any
517
        if (null !== $funcdata->fields['relcomment']) {
518
            echo \sprintf('%s--%s', \PHP_EOL, \PHP_EOL);
519
            echo \sprintf('-- Name: %s; Type: COMMENT; Schema: %s; Owner: %s', $fname, $funcdata->fields['nspname'], $funcdata->fields['relowner']);
520
            echo \sprintf('%s--%s%s', \PHP_EOL, \PHP_EOL, \PHP_EOL);
521
            echo \sprintf("%sCOMMENT ON FUNCTION %s.%s IS '%s';%s", \PHP_EOL, $funcdata->fields['nspname'], $fname, $funcdata->fields['relcomment'], \PHP_EOL);
522
            //echo '<p class="comment">', $this->misc->printVal($funcdata->fields['relcomment']), '</p>' . PHP_EOL;
523
        }
524
525
        echo \sprintf('%s</code></pre>', \PHP_EOL);
526
527
        echo '</td></tr>' . \PHP_EOL;
528
529
        echo '</table>' . \PHP_EOL;
530
531
        return $this->_printNavLinks('functions-properties', $func_full);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_printNavL...roperties', $func_full) returns the type void which is incompatible with the documented return type string.
Loading history...
532
    }
533
534
    /**
535
     * Show read only properties of a function.
536
     *
537
     * @param mixed $msg
538
     */
539
    public function doProperties($msg = '')
540
    {
541
        $data = $this->misc->getDatabaseAccessor();
542
543
        $this->printTrail('function');
544
        $this->printTabs('function', 'definition');
545
        $this->printTitle($this->lang['strproperties'], 'pg.function');
546
        $this->printMsg($msg);
547
548
        $funcdata = $data->getFunction($_REQUEST['function_oid']);
549
        $func_full = '';
550
551
        if (0 >= $funcdata->recordCount()) {
552
            echo "<p>{$this->lang['strnodata']}</p>" . \PHP_EOL;
553
554
            return $this->_printNavLinks('functions-properties', $func_full);
555
        }
556
        // Deal with named parameters
557
        $args = $this->_getPropertiesArgs($funcdata);
0 ignored issues
show
Bug introduced by
It seems like $funcdata can also be of type integer; however, parameter $funcdata of PHPPgAdmin\Controller\Fu...r::_getPropertiesArgs() does only seem to accept ADORecordSet, maybe add an additional type check? ( Ignorable by Annotation )

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

557
        $args = $this->_getPropertiesArgs(/** @scrutinizer ignore-type */ $funcdata);
Loading history...
558
559
        // Show comment if any
560
        if (null !== $funcdata->fields['procomment']) {
561
            echo '<p class="comment">', $this->misc->printVal($funcdata->fields['procomment']), '</p>' . \PHP_EOL;
562
        }
563
564
        $funcdata->fields['proretset'] = $data->phpBool($funcdata->fields['proretset']);
565
        $func_full = $funcdata->fields['proname'] . '(' . $funcdata->fields['proarguments'] . ')';
566
567
        echo '<table style="width: 95%">' . \PHP_EOL;
568
569
        echo \sprintf('<tr><th class="data">%s</th>%s', $this->lang['strfunction'], \PHP_EOL);
570
        echo \sprintf('<th class="data">%s</th>%s', $this->lang['strarguments'], \PHP_EOL);
571
        echo \sprintf('<th class="data">%s</th>%s', $this->lang['strreturns'], \PHP_EOL);
572
        echo \sprintf('<th class="data">%s</th></tr>%s', $this->lang['strproglanguage'], \PHP_EOL);
573
574
        echo '<tr><td class="data1">', $this->misc->printVal($funcdata->fields['proname']), '</td>' . \PHP_EOL;
575
        echo '<td class="data1">', $this->misc->printVal($args), '</td>' . \PHP_EOL;
576
        echo '<td class="data1">';
577
578
        if ($funcdata->fields['proretset']) {
579
            echo 'setof ';
580
        }
581
582
        echo $this->misc->printVal($funcdata->fields['proresult']), '</td>' . \PHP_EOL;
583
        echo '<td class="data1">', $this->misc->printVal($funcdata->fields['prolanguage']), '</td></tr>' . \PHP_EOL;
584
585
        $fnlang = \mb_strtolower($funcdata->fields['prolanguage']);
586
587
        if ('c' === $fnlang) {
588
            echo "<tr><th class=\"data\" colspan=\"2\">{$this->lang['strobjectfile']}</th>" . \PHP_EOL;
589
            echo "<th class=\"data\" colspan=\"2\">{$this->lang['strlinksymbol']}</th></tr>" . \PHP_EOL;
590
            echo '<tr><td class="data1" colspan="2">', $this->misc->printVal($funcdata->fields['probin']), '</td>' . \PHP_EOL;
591
            echo '<td class="data1" colspan="2">', $this->misc->printVal($funcdata->fields['prosrc']), '</td></tr>' . \PHP_EOL;
592
        } elseif ('internal' === $fnlang) {
593
            echo "<tr><th class=\"data\" colspan=\"4\">{$this->lang['strlinksymbol']}</th></tr>" . \PHP_EOL;
594
            echo '<tr><td class="data1" colspan="4">', $this->misc->printVal($funcdata->fields['prosrc']), '</td></tr>' . \PHP_EOL;
595
        } else {
596
            echo '<tr><td class="data1" colspan="4">';
597
            echo \sprintf('<pre><code class="%s hljs">%s</code></pre>', $fnlang, $funcdata->fields['prosrc']);
598
            echo '</td></tr>' . \PHP_EOL;
599
        }
600
601
        // Display function cost options
602
        if ($data->hasFunctionCosting()) {
603
            echo "<tr><th class=\"data required\" colspan=\"4\">{$this->lang['strfunctioncosting']}</th></tr>" . \PHP_EOL;
604
            echo "<td class=\"data1\" colspan=\"2\">{$this->lang['strexecutioncost']}: ", $this->misc->printVal($funcdata->fields['procost']), ' </td>';
605
            echo "<td class=\"data1\" colspan=\"2\">{$this->lang['strresultrows']}: ", $this->misc->printVal($funcdata->fields['prorows']), ' </td>';
606
        }
607
608
        // Show flags
609
        if (\is_array($data->funcprops) && 0 < \count($data->funcprops)) {
610
            // Fetch an array of the function properties
611
            $funcprops = $data->getFunctionProperties($funcdata->fields);
0 ignored issues
show
Bug introduced by
$funcdata->fields of type boolean is incompatible with the type array expected by parameter $f of PHPPgAdmin\Database\Post...getFunctionProperties(). ( Ignorable by Annotation )

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

611
            $funcprops = $data->getFunctionProperties(/** @scrutinizer ignore-type */ $funcdata->fields);
Loading history...
612
            echo "<tr><th class=\"data\" colspan=\"4\">{$this->lang['strproperties']}</th></tr>" . \PHP_EOL;
613
            echo '<tr><td class="data1" colspan="4">' . \PHP_EOL;
614
615
            foreach ($funcprops as $v) {
616
                echo $this->misc->printVal($v), '<br />' . \PHP_EOL;
617
            }
618
            echo '</td></tr>' . \PHP_EOL;
619
        }
620
621
        echo "<tr><td class=\"data1\" colspan=\"5\">{$this->lang['strowner']}: ", \htmlspecialchars($funcdata->fields['proowner']), \PHP_EOL;
622
        echo '</td></tr>' . \PHP_EOL;
623
        echo '</table>' . \PHP_EOL;
624
625
        return $this->_printNavLinks('functions-properties', $func_full);
626
    }
627
628
    /**
629
     * Show confirmation of drop and perform actual drop.
630
     *
631
     * @param mixed $confirm
632
     */
633
    public function doDrop($confirm)
634
    {
635
        $data = $this->misc->getDatabaseAccessor();
636
637
        if (empty($_REQUEST['function']) && empty($_REQUEST['ma'])) {
638
            return $this->doDefault($this->lang['strspecifyfunctiontodrop']);
639
        }
640
641
        if ($confirm) {
642
            $this->printTrail('function');
643
            $this->printTabs('function', 'definition');
644
            $this->printTitle($this->lang['strdrop'], 'pg.function.drop');
645
646
            echo '<form action="' . \containerInstance()->subFolder . '/src/views/functions" method="post">' . \PHP_EOL;
647
648
            //If multi drop
649
            if (isset($_REQUEST['ma'])) {
650
                foreach ($_REQUEST['ma'] as $v) {
651
                    $a = \unserialize(\htmlspecialchars_decode($v, \ENT_QUOTES));
652
                    echo '<p>', \sprintf($this->lang['strconfdropfunction'], $this->misc->printVal($a['function'])), '</p>' . \PHP_EOL;
653
                    echo '<input type="hidden" name="function[]" value="', \htmlspecialchars($a['function']), '" />' . \PHP_EOL;
654
                    echo '<input type="hidden" name="function_oid[]" value="', \htmlspecialchars($a['function_oid']), '" />' . \PHP_EOL;
655
                }
656
            } else {
657
                echo '<p>', \sprintf($this->lang['strconfdropfunction'], $this->misc->printVal($_REQUEST['function'])), '</p>' . \PHP_EOL;
658
                echo '<input type="hidden" name="function" value="', \htmlspecialchars($_REQUEST['function']), '" />' . \PHP_EOL;
659
                echo '<input type="hidden" name="function_oid" value="', \htmlspecialchars($_REQUEST['function_oid']), '" />' . \PHP_EOL;
660
            }
661
662
            echo '<input type="hidden" name="action" value="drop" />' . \PHP_EOL;
663
664
            echo $this->view->form;
665
            echo "<p><input type=\"checkbox\" id=\"cascade\" name=\"cascade\" /><label for=\"cascade\">{$this->lang['strcascade']}</label></p>" . \PHP_EOL;
666
            echo "<input type=\"submit\" name=\"drop\" value=\"{$this->lang['strdrop']}\" />" . \PHP_EOL;
667
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$this->lang['strcancel']}\" />" . \PHP_EOL;
668
            echo '</form>' . \PHP_EOL;
669
        } else {
670
            if (\is_array($_POST['function_oid'])) {
671
                $msg = '';
672
                $status = $data->beginTransaction();
673
674
                if (0 === $status) {
675
                    foreach ($_POST['function_oid'] as $k => $s) {
676
                        $status = $data->dropFunction($s, isset($_POST['cascade']));
677
678
                        if (0 === $status) {
679
                            $msg .= \sprintf(
680
                                '%s: %s<br />',
681
                                \htmlentities($_POST['function'][$k], \ENT_QUOTES, 'UTF-8'),
682
                                $this->lang['strfunctiondropped']
683
                            );
684
                        } else {
685
                            $data->endTransaction();
686
                            $this->doDefault(\sprintf(
687
                                '%s%s: %s<br />',
688
                                $msg,
689
                                \htmlentities($_POST['function'][$k], \ENT_QUOTES, 'UTF-8'),
690
                                $this->lang['strfunctiondroppedbad']
691
                            ));
692
693
                            return;
694
                        }
695
                    }
696
                }
697
698
                if (0 === $data->endTransaction()) {
699
                    // Everything went fine, back to the Default page....
700
                    $this->view->setReloadBrowser(true);
701
                    $this->doDefault($msg);
702
                } else {
703
                    $this->doDefault($this->lang['strfunctiondroppedbad']);
704
                }
705
            } else {
706
                $status = $data->dropFunction($_POST['function_oid'], isset($_POST['cascade']));
707
708
                if (0 === $status) {
709
                    $this->view->setReloadBrowser(true);
710
                    $this->doDefault($this->lang['strfunctiondropped']);
711
                } else {
712
                    $this->doDefault($this->lang['strfunctiondroppedbad']);
713
                }
714
            }
715
        }
716
    }
717
718
    /**
719
     * Displays a screen where they can enter a new function.
720
     *
721
     * @param string $msg  message to display
722
     * @param mixed  $szJS
723
     */
724
    public function doCreate($msg = '', $szJS = ''): void
725
    {
726
        $data = $this->misc->getDatabaseAccessor();
727
728
        $this->printTrail('schema');
729
        $_POST['formFunction'] = $this->getPostParam('formFunction', '');
730
731
        $_POST['formArguments'] = $this->getPostParam('formArguments', '');
732
733
        $_POST['formReturns'] = $this->getPostParam('formReturns', '');
734
735
        $this->coalesceArr($_POST, 'formLanguage', $_REQUEST['language'] ?? 'sql');
736
737
        $_POST['formDefinition'] = $this->getPostParam('formDefinition', '');
738
739
        $_POST['formObjectFile'] = $this->getPostParam('formObjectFile', '');
740
741
        $_POST['formLinkSymbol'] = $this->getPostParam('formLinkSymbol', '');
742
743
        $_POST['formProperties'] = $this->getPostParam('formProperties', $data->defaultprops);
744
745
        $_POST['formSetOf'] = $this->getPostParam('formSetOf', '');
746
747
        $_POST['formArray'] = $this->getPostParam('formArray', '');
748
749
        $_POST['formCost'] = $this->getPostParam('formCost', '');
750
751
        $_POST['formRows'] = $this->getPostParam('formRows', '');
752
753
        $_POST['formComment'] = $this->getPostParam('formComment', '');
754
755
        $types = $data->getTypes(true, true, true);
756
        $langs = $data->getLanguages(true);
757
        $fnlang = \mb_strtolower($_POST['formLanguage']);
758
759
        switch ($fnlang) {
760
            case 'c':
761
                $this->printTitle($this->lang['strcreatecfunction'], 'pg.function.create.c');
762
763
                break;
764
            case 'internal':
765
                $this->printTitle($this->lang['strcreateinternalfunction'], 'pg.function.create.internal');
766
767
                break;
768
769
            default:
770
                $this->printTitle($this->lang['strcreateplfunction'], 'pg.function.create.pl');
771
772
                break;
773
        }
774
        $this->printMsg($msg);
775
776
        // Create string for return type list
777
        $szTypes = '';
778
779
        while (!$types->EOF) {
780
            $szSelected = '';
781
782
            if ($types->fields['typname'] === $_POST['formReturns']) {
783
                $szSelected = ' selected="selected"';
784
            }
785
            // this variable is include in the JS code bellow, so we need to ENT_QUOTES
786
            $szTypes .= '<option value="' . \htmlspecialchars($types->fields['typname'], \ENT_QUOTES) . "\"{$szSelected}>";
787
            $szTypes .= \htmlspecialchars($types->fields['typname'], \ENT_QUOTES) . '</option>';
788
            $types->moveNext();
789
        }
790
791
        $szFunctionName = "<td class=\"data1\"><input name=\"formFunction\" size=\"16\" maxlength=\"{$data->_maxNameLen}\" value=\"" .
792
        \htmlspecialchars($_POST['formFunction']) . '" /></td>';
793
794
        $szArguments = '<td class="data1"><input name="formArguments" style="width:100%;" size="16" value="' .
795
        \htmlspecialchars($_POST['formArguments']) . '" /></td>';
796
797
        $szSetOfSelected = '';
798
        $szNotSetOfSelected = '';
799
800
        if ('' === $_POST['formSetOf']) {
801
            $szNotSetOfSelected = ' selected="selected"';
802
        } elseif ('SETOF' === $_POST['formSetOf']) {
803
            $szSetOfSelected = ' selected="selected"';
804
        }
805
        $szReturns = '<td class="data1" colspan="2">';
806
        $szReturns .= '<select name="formSetOf">';
807
        $szReturns .= "<option value=\"\"{$szNotSetOfSelected}></option>";
808
        $szReturns .= "<option value=\"SETOF\"{$szSetOfSelected}>SETOF</option>";
809
        $szReturns .= '</select>';
810
811
        $szReturns .= '<select class="select2" name="formReturns">' . $szTypes . '</select>';
812
813
        // Create string array type selector
814
815
        $szArraySelected = '';
816
        $szNotArraySelected = '';
817
818
        if ('' === $_POST['formArray']) {
819
            $szNotArraySelected = ' selected="selected"';
820
        } elseif ('[]' === $_POST['formArray']) {
821
            $szArraySelected = ' selected="selected"';
822
        }
823
824
        $szReturns .= '<select name="formArray">';
825
        $szReturns .= "<option value=\"\"{$szNotArraySelected}></option>";
826
        $szReturns .= "<option value=\"[]\"{$szArraySelected}>[ ]</option>";
827
        $szReturns .= "</select>\n</td>";
828
829
        // Create string for language
830
        $szLanguage = '<td class="data1">';
831
832
        if ('c' === $fnlang || 'internal' === $fnlang) {
833
            $szLanguage .= $_POST['formLanguage'] . \PHP_EOL;
834
            $szLanguage .= "<input type=\"hidden\" name=\"formLanguage\" value=\"{$_POST['formLanguage']}\" />" . \PHP_EOL;
835
        } else {
836
            $szLanguage .= '<select name="formLanguage">' . \PHP_EOL;
837
838
            while (!$langs->EOF) {
839
                $szSelected = '';
840
841
                if ($langs->fields['lanname'] === $_POST['formLanguage']) {
842
                    $szSelected = ' selected="selected"';
843
                }
844
845
                if ('c' !== \mb_strtolower($langs->fields['lanname']) && 'internal' !== \mb_strtolower($langs->fields['lanname'])) {
846
                    $szLanguage .= '<option value="' . \htmlspecialchars($langs->fields['lanname']) . "\"{$szSelected}>\n" .
847
                    $this->misc->printVal($langs->fields['lanname']) . '</option>';
848
                }
849
850
                $langs->moveNext();
851
            }
852
            $szLanguage .= '</select>' . \PHP_EOL;
853
        }
854
855
        $szLanguage .= '</td>';
856
        $szJSArguments = "<tr><th class=\"data\" colspan=\"7\">{$this->lang['strarguments']}</th></tr>";
857
        $arrayModes = ['IN', 'OUT', 'INOUT'];
858
        $szModes = '<select name="formArgModes[]" style="width:100%;">';
859
860
        foreach ($arrayModes as $pV) {
861
            $szModes .= "<option value=\"{$pV}\">{$pV}</option>";
862
        }
863
        $szModes .= '</select>';
864
        $szArgReturns = '<select name="formArgArray[]">';
865
        $szArgReturns .= '<option value=""></option>';
866
        $szArgReturns .= '<option value="[]">[]</option>';
867
        $szArgReturns .= '</select>';
868
        $subfolder = \containerInstance()->subFolder;
869
870
        if (!empty($this->conf['theme'])) {
871
            $szImgPath = \containerInstance()->subFolder . "/assets/images/themes/{$this->conf['theme']}";
872
        } else {
873
            $szImgPath = \containerInstance()->subFolder . '/assets/images/themes/default';
874
        }
875
876
        if (empty($msg)) {
877
            $szJSTRArg = "<script type=\"text/javascript\" >addArg('{$subfolder}');</script>" . \PHP_EOL;
878
        } else {
879
            $szJSTRArg = '';
880
        }
881
        $szJSAddTR = "<tr id=\"parent_add_tr\" onclick=\"addArg('{$subfolder}');\" onmouseover=\"this.style.cursor='pointer'\">" . \PHP_EOL;
882
        $szJSAddTR .= '<td style="text-align: right" colspan="6" class="data3"><table><tr><td class="data3">';
883
        $szJSAddTR .= "<img src=\"{$szImgPath}/AddArguments.png\" alt=\"Add Argument\" /></td>";
884
        $szJSAddTR .= "<td class=\"data3\"><span style=\"font-size: 8pt\">{$this->lang['strargadd']}</span></td></tr></table></td>\n</tr>" . \PHP_EOL;
885
886
        echo '<script src="' . \containerInstance()->subFolder . "/assets/js/functions.js\" type=\"text/javascript\"></script>
887
		<script type=\"text/javascript\">
888
			//<![CDATA[
889
			var g_types_select = '<select class=\"select2\" name=\"formArgType[]\">{$szTypes}</select>{$szArgReturns}';
890
			var g_modes_select = '{$szModes}';
891
			var g_name = '';
892
			var g_lang_strargremove = '", \htmlspecialchars($this->lang['strargremove'], \ENT_QUOTES), "';
893
			var g_lang_strargnoargs = '", \htmlspecialchars($this->lang['strargnoargs'], \ENT_QUOTES), "';
894
			var g_lang_strargenableargs = '", \htmlspecialchars($this->lang['strargenableargs'], \ENT_QUOTES), "';
895
			var g_lang_strargnorowabove = '", \htmlspecialchars($this->lang['strargnorowabove'], \ENT_QUOTES), "';
896
			var g_lang_strargnorowbelow = '", \htmlspecialchars($this->lang['strargnorowbelow'], \ENT_QUOTES), "';
897
			var g_lang_strargremoveconfirm = '", \htmlspecialchars($this->lang['strargremoveconfirm'], \ENT_QUOTES), "';
898
			var g_lang_strargraise = '", \htmlspecialchars($this->lang['strargraise'], \ENT_QUOTES), "';
899
			var g_lang_strarglower = '", \htmlspecialchars($this->lang['strarglower'], \ENT_QUOTES), "';
900
			//]]>
901
		</script>
902
		";
903
        echo '<form action="' . \containerInstance()->subFolder . '/src/views/functions" method="post">' . \PHP_EOL;
904
        echo '<table><tbody id="args_table">' . \PHP_EOL;
905
        echo "<tr><th class=\"data required\">{$this->lang['strname']}</th>" . \PHP_EOL;
906
        echo "<th class=\"data required\" colspan=\"2\">{$this->lang['strreturns']}</th>" . \PHP_EOL;
907
        echo "<th class=\"data required\">{$this->lang['strproglanguage']}</th></tr>" . \PHP_EOL;
908
        echo '<tr>' . \PHP_EOL;
909
        echo "{$szFunctionName}\n";
910
        echo "{$szReturns}\n";
911
        echo "{$szLanguage}\n";
912
        echo '</tr>' . \PHP_EOL;
913
        echo "{$szJSArguments}\n";
914
        echo '<tr>' . \PHP_EOL;
915
        echo "<th class=\"data required\">{$this->lang['strargmode']}</th>" . \PHP_EOL;
916
        echo "<th class=\"data required\">{$this->lang['strname']}</th>" . \PHP_EOL;
917
        echo "<th class=\"data required\" colspan=\"2\">{$this->lang['strargtype']}</th>" . \PHP_EOL;
918
        echo '</tr>' . \PHP_EOL;
919
        echo "{$szJSAddTR}\n";
920
921
        if ('c' === $fnlang) {
922
            echo "<tr><th class=\"data required\" colspan=\"2\">{$this->lang['strobjectfile']}</th>" . \PHP_EOL;
923
            echo "<th class=\"data\" colspan=\"2\">{$this->lang['strlinksymbol']}</th></tr>" . \PHP_EOL;
924
            echo '<tr><td class="data1" colspan="2"><input type="text" name="formObjectFile" style="width:100%" value="',
925
            \htmlspecialchars($_POST['formObjectFile']), '" /></td>' . \PHP_EOL;
926
            echo '<td class="data1" colspan="2"><input type="text" name="formLinkSymbol" style="width:100%" value="',
927
            \htmlspecialchars($_POST['formLinkSymbol']), '" /></td></tr>' . \PHP_EOL;
928
        } elseif ('internal' === $fnlang) {
929
            echo "<tr><th class=\"data\" colspan=\"4\">{$this->lang['strlinksymbol']}</th></tr>" . \PHP_EOL;
930
            echo '<tr><td class="data1" colspan="4"><input type="text" name="formLinkSymbol" style="width:100%" value="',
931
            \htmlspecialchars($_POST['formLinkSymbol']), '" /></td></tr>' . \PHP_EOL;
932
        } else {
933
            echo "<tr><th class=\"data required\" colspan=\"4\">{$this->lang['strdefinition']}</th></tr>" . \PHP_EOL;
934
            echo '<tr><td class="data1" colspan="4">';
935
            echo '<textarea style="width:100%;" rows="20" cols="50" name="formDefinition">';
936
            echo \htmlspecialchars($_POST['formDefinition']);
937
            echo '</textarea></td></tr>' . \PHP_EOL;
938
        }
939
940
        // Display function comment
941
        echo "<tr><th class=\"data\" colspan=\"4\">{$this->lang['strcomment']}</th></tr>" . \PHP_EOL;
942
        echo '<tr><td class="data1" colspan="4"><textarea style="width:100%;" name="formComment" rows="3" cols="50">',
943
        \htmlspecialchars($_POST['formComment']), '</textarea></td></tr>' . \PHP_EOL;
944
945
        // Display function cost options
946
        if ($data->hasFunctionCosting()) {
947
            echo "<tr><th class=\"data required\" colspan=\"4\">{$this->lang['strfunctioncosting']}</th></tr>" . \PHP_EOL;
948
            echo "<td class=\"data1\" colspan=\"2\">{$this->lang['strexecutioncost']}: <input name=\"formCost\" size=\"16\" value=\"" .
949
            \htmlspecialchars($_POST['formCost']) . '" /></td>';
950
            echo "<td class=\"data1\" colspan=\"2\">{$this->lang['strresultrows']}: <input name=\"formRows\" size=\"16\" value=\"" .
951
            \htmlspecialchars($_POST['formRows']) . '" /></td>';
952
        }
953
954
        // Display function properties
955
        if (\is_array($data->funcprops) && 0 < \count($data->funcprops)) {
956
            echo "<tr><th class=\"data required\" colspan=\"4\">{$this->lang['strproperties']}</th></tr>" . \PHP_EOL;
957
            echo '<tr><td class="data1" colspan="4">' . \PHP_EOL;
958
            $i = 0;
959
960
            foreach ($data->funcprops as $k => $v) {
961
                echo "<select name=\"formProperties[{$i}]\">" . \PHP_EOL;
962
963
                foreach ($v as $p) {
964
                    echo '<option value="', \htmlspecialchars($p), '"',
965
                    ($_POST['formProperties'][$i] === $p) ? ' selected="selected"' : '',
966
                    '>', $this->misc->printVal($p), '</option>' . \PHP_EOL;
967
                }
968
                echo '</select><br />' . \PHP_EOL;
969
                ++$i;
970
            }
971
            echo '</td></tr>' . \PHP_EOL;
972
        }
973
        echo '</tbody></table>' . \PHP_EOL;
974
        echo $szJSTRArg;
975
        echo '<p><input type="hidden" name="action" value="save_create" />' . \PHP_EOL;
976
        echo $this->view->form;
977
        echo "<input type=\"submit\" value=\"{$this->lang['strcreate']}\" />" . \PHP_EOL;
978
        echo \sprintf('<input type="submit" name="cancel" value="%s"  /></p>%s', $this->lang['strcancel'], \PHP_EOL);
979
        echo '</form>' . \PHP_EOL;
980
        echo $szJS;
981
    }
982
983
    /**
984
     * Actually creates the new function in the database.
985
     */
986
    public function doSaveCreate(): void
987
    {
988
        $data = $this->misc->getDatabaseAccessor();
989
990
        $fnlang = \mb_strtolower($_POST['formLanguage']);
991
992
        if ('c' === $fnlang) {
993
            $def = [$_POST['formObjectFile'], $_POST['formLinkSymbol']];
994
        } elseif ('internal' === $fnlang) {
995
            $def = $_POST['formLinkSymbol'];
996
        } else {
997
            $def = $_POST['formDefinition'];
998
        }
999
1000
        $szJS = '';
1001
1002
        echo '<script src="' . \containerInstance()->subFolder . '/assets/js/functions.js" type="text/javascript"></script>';
1003
        echo '<script type="text/javascript">' . $this->_buildJSData() . '</script>';
1004
1005
        if (!empty($_POST['formArgName'])) {
1006
            $szJS = $this->_buildJSRows($this->_buildFunctionArguments($_POST));
1007
        } else {
1008
            $subfolder = \containerInstance()->subFolder;
1009
            $szJS = '<script type="text/javascript" src="' . \containerInstance()->subFolder . '/assets/js/functions.js">noArgsRebuild(addArg("' . $subfolder . '"));</script>';
1010
        }
1011
1012
        $cost = (isset($_POST['formCost'])) ? $_POST['formCost'] : null;
1013
1014
        if ('' === $cost || !\is_numeric($cost) || (int) $cost !== $cost || 0 > $cost) {
1015
            $cost = null;
1016
        }
1017
1018
        $rows = (isset($_POST['formRows'])) ? $_POST['formRows'] : null;
1019
1020
        if ('' === $rows || !\is_numeric($rows) || (int) $rows !== $rows) {
1021
            $rows = null;
1022
        }
1023
1024
        // Check that they've given a name and a definition
1025
        if ('' === $_POST['formFunction']) {
1026
            $this->doCreate($this->lang['strfunctionneedsname'], $szJS);
1027
        } elseif ('internal' !== $fnlang && !$def) {
1028
            $this->doCreate($this->lang['strfunctionneedsdef'], $szJS);
1029
        } else {
1030
            // Append array symbol to type if chosen
1031
            $status = $data->createFunction(
1032
                $_POST['formFunction'],
1033
                empty($_POST['nojs']) ? $this->_buildFunctionArguments($_POST) : $_POST['formArguments'],
1034
                $_POST['formReturns'] . $_POST['formArray'],
1035
                $def,
1036
                $_POST['formLanguage'],
1037
                $_POST['formProperties'],
1038
                'SETOF' === $_POST['formSetOf'],
1039
                $cost,
1040
                $rows,
1041
                $_POST['formComment'],
1042
                false
1043
            );
1044
1045
            if (0 === $status) {
1046
                $this->doDefault($this->lang['strfunctioncreated']);
1047
            } else {
1048
                $this->doCreate($this->lang['strfunctioncreatedbad'], $szJS);
1049
            }
1050
        }
1051
    }
1052
1053
    private function _printNavLinks(string $place, string $func_full = ''): void
1054
    {
1055
        if ('functions-properties' === $place) {
1056
            $navlinks = [
1057
                'showall' => [
1058
                    'attr' => [
1059
                        'href' => [
1060
                            'url' => 'functions',
1061
                            'urlvars' => [
1062
                                'server' => $_REQUEST['server'],
1063
                                'database' => $_REQUEST['database'],
1064
                                'schema' => $_REQUEST['schema'],
1065
                            ],
1066
                        ],
1067
                    ],
1068
                    'content' => $this->lang['strshowallfunctions'],
1069
                ],
1070
                'alter' => [
1071
                    'attr' => [
1072
                        'href' => [
1073
                            'url' => 'functions',
1074
                            'urlvars' => [
1075
                                'action' => 'edit',
1076
                                'server' => $_REQUEST['server'],
1077
                                'database' => $_REQUEST['database'],
1078
                                'schema' => $_REQUEST['schema'],
1079
                                'function' => $_REQUEST['function'],
1080
                                'function_oid' => $_REQUEST['function_oid'],
1081
                            ],
1082
                        ],
1083
                    ],
1084
                    'content' => $this->lang['stralter'],
1085
                ],
1086
                'drop' => [
1087
                    'attr' => [
1088
                        'href' => [
1089
                            'url' => 'functions',
1090
                            'urlvars' => [
1091
                                'action' => 'confirm_drop',
1092
                                'server' => $_REQUEST['server'],
1093
                                'database' => $_REQUEST['database'],
1094
                                'schema' => $_REQUEST['schema'],
1095
                                'function' => $func_full,
1096
                                'function_oid' => $_REQUEST['function_oid'],
1097
                            ],
1098
                        ],
1099
                    ],
1100
                    'content' => $this->lang['strdrop'],
1101
                ],
1102
            ];
1103
        } elseif ('functions-functions' === $place) {
1104
            $navlinks = [
1105
                'createpl' => [
1106
                    'attr' => [
1107
                        'href' => [
1108
                            'url' => 'functions',
1109
                            'urlvars' => [
1110
                                'action' => 'create',
1111
                                'server' => $_REQUEST['server'],
1112
                                'database' => $_REQUEST['database'],
1113
                                'schema' => $_REQUEST['schema'],
1114
                            ],
1115
                        ],
1116
                    ],
1117
                    'content' => $this->lang['strcreateplfunction'],
1118
                ],
1119
                'createinternal' => [
1120
                    'attr' => [
1121
                        'href' => [
1122
                            'url' => 'functions',
1123
                            'urlvars' => [
1124
                                'action' => 'create',
1125
                                'language' => 'internal',
1126
                                'server' => $_REQUEST['server'],
1127
                                'database' => $_REQUEST['database'],
1128
                                'schema' => $_REQUEST['schema'],
1129
                            ],
1130
                        ],
1131
                    ],
1132
                    'content' => $this->lang['strcreateinternalfunction'],
1133
                ],
1134
                'createc' => [
1135
                    'attr' => [
1136
                        'href' => [
1137
                            'url' => 'functions',
1138
                            'urlvars' => [
1139
                                'action' => 'create',
1140
                                'language' => 'C',
1141
                                'server' => $_REQUEST['server'],
1142
                                'database' => $_REQUEST['database'],
1143
                                'schema' => $_REQUEST['schema'],
1144
                            ],
1145
                        ],
1146
                    ],
1147
                    'content' => $this->lang['strcreatecfunction'],
1148
                ],
1149
            ];
1150
        } else {
1151
            return;
1152
        }
1153
1154
        $this->printNavLinks($navlinks, $place, \get_defined_vars());
1155
    }
1156
1157
    private function _getNamedParamsArgs($data, $fndata)
1158
    {
1159
        if (isset($fndata->fields['proallarguments'])) {
1160
            $args_arr = $data->phpArray($fndata->fields['proallarguments']);
1161
        } else {
1162
            $args_arr = \explode(', ', $fndata->fields['proarguments']);
1163
        }
1164
        $names_arr = $data->phpArray($fndata->fields['proargnames']);
1165
        $modes_arr = $data->phpArray($fndata->fields['proargmodes']);
1166
        $args = '';
1167
        $args_arr_size = \count($args_arr);
1168
1169
        for ($i = 0; $i < $args_arr_size; ++$i) {
1170
            if (0 !== $i) {
1171
                $args .= ', ';
1172
            }
1173
1174
            if (isset($modes_arr[$i])) {
1175
                switch ($modes_arr[$i]) {
1176
                    case 'i':
1177
                        $args .= ' IN ';
1178
1179
                        break;
1180
                    case 'o':
1181
                        $args .= ' OUT ';
1182
1183
                        break;
1184
                    case 'b':
1185
                        $args .= ' INOUT ';
1186
1187
                        break;
1188
                    case 'v':
1189
                        $args .= ' VARIADIC ';
1190
1191
                        break;
1192
                    case 't':
1193
                        $args .= ' TABLE ';
1194
1195
                        break;
1196
                }
1197
            }
1198
1199
            if (isset($names_arr[$i]) && '' !== $names_arr[$i]) {
1200
                $data->fieldClean($names_arr[$i]);
1201
                $args .= '"' . $names_arr[$i] . '" ';
1202
            }
1203
            $args .= $args_arr[$i];
1204
        }
1205
1206
        return $args;
1207
    }
1208
1209
    /**
1210
     * Build out the function arguments string.
1211
     *
1212
     * @param array $arrayVars
1213
     *
1214
     * @return string the imploded array vars
1215
     */
1216
    private function _buildFunctionArguments($arrayVars)
1217
    {
1218
        if (isset($_POST['formArgName'])) {
1219
            $arrayArgs = [];
1220
1221
            foreach ($arrayVars['formArgName'] as $pK => $pV) {
1222
                $arrayArgs[] = $arrayVars['formArgModes'][$pK] . ' ' . \trim($pV) . ' ' . \trim($arrayVars['formArgType'][$pK]) . $arrayVars['formArgArray'][$pK];
1223
            }
1224
1225
            return \implode(',', $arrayArgs);
1226
        }
1227
1228
        return '';
1229
    }
1230
1231
    /**
1232
     * Build out JS to re-create table rows for arguments.
1233
     *
1234
     * @param string $szArgs args to parse
1235
     */
1236
    private function _buildJSRows($szArgs)
1237
    {
1238
        $arrayModes = ['IN', 'OUT', 'INOUT'];
1239
        $arrayArgs = \explode(',', $szArgs);
1240
        $arrayProperArgs = [];
1241
        $nC = 0;
1242
        $szReturn = '';
1243
        $szMode = [];
1244
1245
        foreach ($arrayArgs as $pV) {
1246
            $arrayWords = \explode(' ', $pV);
1247
1248
            if (true === \in_array($arrayWords[0], $arrayModes, true)) {
1249
                $szMode = $arrayWords[0];
1250
                \array_shift($arrayWords);
1251
            }
1252
            $szArgName = \array_shift($arrayWords);
1253
1254
            if (false === \mb_strpos($arrayWords[\count($arrayWords) - 1], '[]')) {
1255
                $szArgType = \implode(' ', $arrayWords);
1256
                $bArgIsArray = 'false';
1257
            } else {
1258
                $szArgType = \str_replace('[]', '', \implode(' ', $arrayWords));
1259
                $bArgIsArray = 'true';
1260
            }
1261
            $arrayProperArgs[] = [$szMode, $szArgName, $szArgType, $bArgIsArray];
1262
            $subfolder = \containerInstance()->subFolder;
1263
            $szReturn .= '<script type="text/javascript">';
1264
            $szReturn .= "RebuildArgTR('{$szMode}','{$szArgName}','{$szArgType}',new Boolean({$bArgIsArray},{$subfolder}));";
1265
            $szReturn .= '</script>;';
1266
            ++$nC;
1267
        }
1268
1269
        return $szReturn;
1270
    }
1271
1272
    private function _buildJSData()
1273
    {
1274
        $data = $this->misc->getDatabaseAccessor();
1275
1276
        $arrayModes = ['IN', 'OUT', 'INOUT'];
1277
        $arrayTypes = $data->getTypes(true, true, true);
1278
        $arrayPTypes = [];
1279
        $arrayPModes = [];
1280
1281
        while (!$arrayTypes->EOF) {
1282
            $arrayPTypes[] = "'" . $arrayTypes->fields['typname'] . "'";
1283
            $arrayTypes->moveNext();
1284
        }
1285
1286
        foreach ($arrayModes as $pV) {
1287
            $arrayPModes[] = "'{$pV}'";
1288
        }
1289
1290
        $szTypes = 'g_main_types = new Array(' . \implode(',', $arrayPTypes) . ');';
1291
        $szModes = 'g_main_modes = new Array(' . \implode(',', $arrayPModes) . ');';
1292
1293
        return $szTypes . $szModes;
1294
    }
1295
1296
    /**
1297
     * Get the concatenated arguments for a function.
1298
     *
1299
     * @param \ADORecordSet $funcdata The funcdata record
1300
     *
1301
     * @return string The arguments of the function
1302
     */
1303
    private function _getPropertiesArgs($funcdata)
1304
    {
1305
        $data = $this->misc->getDatabaseAccessor();
1306
1307
        if ($data->hasNamedParams()) {
1308
            if (isset($funcdata->fields['proallarguments'])) {
1309
                $args_arr = $data->phpArray($funcdata->fields['proallarguments']);
1310
            } else {
1311
                $args_arr = \explode(', ', $funcdata->fields['proarguments']);
1312
            }
1313
            $names_arr = $data->phpArray($funcdata->fields['proargnames']);
1314
            $modes_arr = $data->phpArray($funcdata->fields['proargmodes']);
1315
            $args = '';
1316
            $args_arr_size = \count($args_arr);
1317
1318
            for ($i = 0; $i < $args_arr_size; ++$i) {
1319
                if (0 !== $i) {
1320
                    $args .= ', ';
1321
                }
1322
1323
                if (isset($modes_arr[$i])) {
1324
                    switch ($modes_arr[$i]) {
1325
                        case 'i':
1326
                            $args .= ' IN ';
1327
1328
                            break;
1329
                        case 'o':
1330
                            $args .= ' OUT ';
1331
1332
                            break;
1333
                        case 'b':
1334
                            $args .= ' INOUT ';
1335
1336
                            break;
1337
                        case 'v':
1338
                            $args .= ' VARIADIC ';
1339
1340
                            break;
1341
                        case 't':
1342
                            $args .= ' TABLE ';
1343
1344
                            break;
1345
                    }
1346
                }
1347
1348
                if (isset($names_arr[$i]) && '' !== $names_arr[$i]) {
1349
                    $data->fieldClean($names_arr[$i]);
1350
                    $args .= '"' . $names_arr[$i] . '" ';
1351
                }
1352
                $args .= $args_arr[$i];
1353
            }
1354
        } else {
1355
            $args = $funcdata->fields['proarguments'];
1356
        }
1357
1358
        return $args;
1359
    }
1360
}
1361