Passed
Push — develop ( 779af6...c8e223 )
by Felipe
04:24
created

ViewsMatviewsTrait::doSaveCreateWiz()   F

Complexity

Conditions 25
Paths 1826

Size

Total Lines 109
Code Lines 62

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 109
rs 2
c 0
b 0
f 0
cc 25
eloc 62
nc 1826
nop 1

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.48
5
 */
6
7
namespace PHPPgAdmin\Traits;
8
9
use PHPPgAdmin\Decorators\Decorator;
10
11
/**
12
 * Common trait for dealing with views or materialized views.
13
 */
14
trait ViewsMatviewsTrait
15
{
16
    public $href = '';
17
    public $misc;
18
    public $view_name;
19
20
    public function doSubTree()
21
    {
22
        $tabs    = $this->misc->getNavTabs($this->keystring);
23
        $items   = $this->adjustTabsForTree($tabs);
1 ignored issue
show
Bug introduced by
It seems like adjustTabsForTree() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

23
        /** @scrutinizer ignore-call */ 
24
        $items   = $this->adjustTabsForTree($tabs);
Loading history...
24
        $reqvars = $this->misc->getRequestVars($this->keystring);
25
26
        $attrs = [
27
            'text'   => Decorator::field('title'),
28
            'icon'   => Decorator::field('icon'),
29
            'action' => Decorator::actionurl(Decorator::field('url'), $reqvars, Decorator::field('urlvars'), [$this->keystring => $_REQUEST[$this->keystring]]),
30
            'branch' => Decorator::ifempty(
31
                Decorator::field('branch'),
32
                '',
33
                Decorator::url(
34
                    Decorator::field('url'),
35
                    Decorator::field('urlvars'),
36
                    $reqvars,
37
                    [
38
                        'action'         => 'tree',
39
                        $this->keystring => $_REQUEST[$this->keystring],
40
                    ]
41
                )
42
            ),
43
        ];
44
45
        return $this->printTree($items, $attrs, $this->keystring);
1 ignored issue
show
Bug introduced by
It seems like printTree() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

45
        return $this->/** @scrutinizer ignore-call */ printTree($items, $attrs, $this->keystring);
Loading history...
46
    }
47
48
    /**
49
     * Ask for select parameters and perform select.
50
     *
51
     * @param mixed $confirm
52
     * @param mixed $msg
53
     */
54
    public function doSelectRows($confirm, $msg = '')
55
    {
56
        $data = $this->misc->getDatabaseAccessor();
57
58
        if ($confirm) {
59
            $this->printTrail($this->keystring);
1 ignored issue
show
Bug introduced by
It seems like printTrail() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

59
            $this->/** @scrutinizer ignore-call */ 
60
                   printTrail($this->keystring);
Loading history...
60
            $this->printTabs($this->keystring, 'select');
1 ignored issue
show
Bug introduced by
It seems like printTabs() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

60
            $this->/** @scrutinizer ignore-call */ 
61
                   printTabs($this->keystring, 'select');
Loading history...
61
            $this->printMsg($msg);
1 ignored issue
show
Bug introduced by
It seems like printMsg() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

61
            $this->/** @scrutinizer ignore-call */ 
62
                   printMsg($msg);
Loading history...
62
63
            $attrs = $data->getTableAttributes($_REQUEST[$this->keystring]);
64
65
            echo '<form action="'.\SUBFOLDER.'/src/views/'.$this->script.'" method="post" id="selectform">';
66
            echo "\n";
67
68
            if ($attrs->recordCount() > 0) {
69
                // JavaScript for select all feature
70
                echo "<script type=\"text/javascript\">\n";
71
                echo "//<![CDATA[\n";
72
                echo "  function selectAll() {\n";
73
                echo "      for (var i=0; i<document.getElementById('selectform').elements.length; i++) {\n";
74
                echo "          var e = document.getElementById('selectform').elements[i];\n";
75
                echo "          if (e.name.indexOf('show') == 0) { \n ";
76
                echo "              e.checked = document.getElementById('selectform').selectall.checked;\n";
77
                echo "          }\n";
78
                echo "      }\n";
79
                echo "  }\n";
80
                echo "//]]>\n";
81
                echo "</script>\n";
82
83
                echo "<table>\n";
84
85
                // Output table header
86
                echo "<tr><th class=\"data\">{$this->lang['strshow']}</th><th class=\"data\">{$this->lang['strcolumn']}</th>";
87
                echo "<th class=\"data\">{$this->lang['strtype']}</th><th class=\"data\">{$this->lang['stroperator']}</th>";
88
                echo "<th class=\"data\">{$this->lang['strvalue']}</th></tr>";
89
90
                $i = 0;
91
                while (!$attrs->EOF) {
92
                    $attrs->fields['attnotnull'] = $data->phpBool($attrs->fields['attnotnull']);
93
                    // Set up default value if there isn't one already
94
                    if (!isset($_REQUEST['values'][$attrs->fields['attname']])) {
95
                        $_REQUEST['values'][$attrs->fields['attname']] = null;
96
                    }
97
98
                    if (!isset($_REQUEST['ops'][$attrs->fields['attname']])) {
99
                        $_REQUEST['ops'][$attrs->fields['attname']] = null;
100
                    }
101
102
                    // Continue drawing row
103
                    $id = (0 == ($i % 2) ? '1' : '2');
104
                    echo "<tr class=\"data{$id}\">\n";
105
                    echo '<td style="white-space:nowrap;">';
106
                    echo '<input type="checkbox" name="show[', htmlspecialchars($attrs->fields['attname']), ']"',
107
                    isset($_REQUEST['show'][$attrs->fields['attname']]) ? ' checked="checked"' : '', ' /></td>';
108
                    echo '<td style="white-space:nowrap;">', $this->misc->printVal($attrs->fields['attname']), '</td>';
109
                    echo '<td style="white-space:nowrap;">', $this->misc->printVal($data->formatType($attrs->fields['type'], $attrs->fields['atttypmod'])), '</td>';
110
                    echo '<td style="white-space:nowrap;">';
111
                    echo "<select name=\"ops[{$attrs->fields['attname']}]\">\n";
112
                    foreach (array_keys($data->selectOps) as $v) {
113
                        echo '<option value="', htmlspecialchars($v), '"', ($_REQUEST['ops'][$attrs->fields['attname']] == $v) ? ' selected="selected"' : '',
114
                        '>', htmlspecialchars($v), "</option>\n";
115
                    }
116
                    echo "</select></td>\n";
117
                    echo '<td style="white-space:nowrap;">', $data->printField(
118
                        "values[{$attrs->fields['attname']}]",
119
                        $_REQUEST['values'][$attrs->fields['attname']],
120
                        $attrs->fields['type']
121
                    ), '</td>';
122
                    echo "</tr>\n";
123
                    ++$i;
124
                    $attrs->moveNext();
125
                }
126
                // Select all checkbox
127
                echo "<tr><td colspan=\"5\"><input type=\"checkbox\" id=\"selectall\" name=\"selectall\" accesskey=\"a\" onclick=\"javascript:selectAll()\" /><label for=\"selectall\">{$this->lang['strselectallfields']}</label></td></tr>";
128
                echo "</table>\n";
129
            } else {
130
                echo "<p>{$this->lang['strinvalidparam']}</p>\n";
131
            }
132
133
            echo "<p><input type=\"hidden\" name=\"action\" value=\"selectrows\" />\n";
134
            echo '<input type="hidden" name="view" value="', htmlspecialchars($_REQUEST[$this->keystring]), "\" />\n";
135
            echo "<input type=\"hidden\" name=\"subject\" value=\"view\" />\n";
136
            echo $this->misc->form;
137
            echo "<input type=\"submit\" name=\"select\" accesskey=\"r\" value=\"{$this->lang['strselect']}\" />\n";
138
            echo "<input type=\"submit\" name=\"cancel\" value=\"{$this->lang['strcancel']}\" /></p>\n";
139
            echo "</form>\n";
140
141
            return;
142
        }
143
        $this->coalesceArr($_POST, 'show', []);
1 ignored issue
show
Bug introduced by
It seems like coalesceArr() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

143
        $this->/** @scrutinizer ignore-call */ 
144
               coalesceArr($_POST, 'show', []);
Loading history...
144
145
        $this->coalesceArr($_POST, 'values', []);
146
147
        $this->coalesceArr($_POST, 'nulls', []);
148
149
        // Verify that they haven't supplied a value for unary operators
150
        foreach ($_POST['ops'] as $k => $v) {
151
            if ('p' == $data->selectOps[$v] && $_POST['values'][$k] != '') {
152
                $this->doSelectRows(true, $this->lang['strselectunary']);
153
154
                return;
155
            }
156
        }
157
158
        if (0 == sizeof($_POST['show'])) {
159
            return $this->doSelectRows(true, $this->lang['strselectneedscol']);
160
        }
161
        // Generate query SQL
162
        $query = $data->getSelectSQL($_REQUEST[$this->keystring], array_keys($_POST['show']), $_POST['values'], $_POST['ops']);
163
164
        $_REQUEST['query']  = $query;
165
        $_REQUEST['return'] = 'schema';
166
167
        $this->setNoOutput(true);
1 ignored issue
show
Bug introduced by
It seems like setNoOutput() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

167
        $this->/** @scrutinizer ignore-call */ 
168
               setNoOutput(true);
Loading history...
168
169
        $display_controller = new DisplayController($this->getContainer());
1 ignored issue
show
Bug introduced by
It seems like getContainer() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

169
        $display_controller = new DisplayController($this->/** @scrutinizer ignore-call */ getContainer());
Loading history...
Bug introduced by
The type PHPPgAdmin\Traits\DisplayController was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
170
171
        return $display_controller->render();
172
    }
173
174
    /**
175
     * Prints the form wizard to create view or materialized view.
176
     */
177
    public function printWizardCreateForm()
178
    {
179
        $data = $this->misc->getDatabaseAccessor();
180
181
        $tables = $data->getTables(true);
182
183
        echo '<form action="'.\SUBFOLDER."/src/views/{$this->script}\" method=\"post\">\n";
184
        echo "<table>\n";
185
        echo "<tr><th class=\"data\">{$this->lang['strtables']}</th></tr>";
186
        echo "<tr>\n<td class=\"data1\">\n";
187
188
        $arrTables = [];
189
        while (!$tables->EOF) {
190
            $arrTmp                      = [];
191
            $arrTmp['schemaname']        = $tables->fields['nspname'];
192
            $arrTmp['tablename']         = $tables->fields['relname'];
193
            $schema_and_name             = $tables->fields['nspname'].'.'.$tables->fields['relname'];
194
            $arrTables[$schema_and_name] = serialize($arrTmp);
195
            $tables->moveNext();
196
        }
197
        echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrTables, 'formTables[]', false, '', true);
198
199
        echo "</td>\n</tr>\n";
200
        echo "</table>\n";
201
        echo "<p><input type=\"hidden\" name=\"action\" value=\"set_params_create\" />\n";
202
        echo $this->misc->form;
203
        echo "<input type=\"submit\" value=\"{$this->lang['strnext']}\" />\n";
204
        echo "<input type=\"submit\" name=\"cancel\" value=\"{$this->lang['strcancel']}\" /></p>\n";
205
        echo "</form>\n";
206
    }
207
208
    /**
209
     * Appends to selected fields.
210
     *
211
     * @param array  $arrTmp    The arr temporary
212
     * @param string $selFields The selected fields
213
     * @param array  $tmpHsh    The temporary hsh
214
     */
215
    private function _appendToSelFields($arrTmp, &$selFields, &$tmpHsh)
216
    {
217
        $field_arr = [$arrTmp['schemaname'], $arrTmp['tablename'], $arrTmp['fieldname']];
218
219
        $field_element = '"'.implode('"."', $field_arr).'"';
220
        if (empty($_POST['dblFldMeth'])) {
221
            // no doublon control
222
            $selFields .= $field_element.', ';
223
        // doublon control
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 12 spaces, found 8
Loading history...
224
        } elseif (empty($tmpHsh[$arrTmp['fieldname']])) {
225
            // field does not exist
226
            $selFields .= $field_element.', ';
227
            $tmpHsh[$arrTmp['fieldname']] = 1;
228
        } elseif ('rename' == $_POST['dblFldMeth']) {
229
            // field exist and must be renamed
230
            ++$tmpHsh[$arrTmp['fieldname']];
231
            $selFields .= $field_element.'  AS  "'.implode('_', $field_arr).'_'.$tmpHsh[$arrTmp['fieldname']].'", ';
232
        }
233
        //  if field already exist, just ignore this one
234
    }
235
236
    private function _getArrLinks()
237
    {
238
        $arrLinks = [];
239
        $count    = 0;
240
        // If we have links, out put the JOIN ... ON statements
241
        if (is_array($_POST['formLink'])) {
242
            // Filter out invalid/blank entries for our links
243
244
            foreach ($_POST['formLink'] as $curLink) {
245
                if (strlen($curLink['leftlink']) && strlen($curLink['rightlink']) && strlen($curLink['operator'])) {
246
                    $arrLinks[] = $curLink;
247
                }
248
            }
249
            // We must perform some magic to make sure that we have a valid join order
250
            $count = sizeof($arrLinks);
251
        }
252
253
        return [$arrLinks, $count];
254
    }
255
256
    /**
257
     * Actually creates the new wizard view in the database.
258
     *
259
     * @param bool $is_materialized true if it's a materialized view, false by default
260
     *
261
     * @return mixed either a sucess message, a redirection, an error message and who knows
262
     */
263
    public function doSaveCreateWiz($is_materialized = false)
264
    {
265
        $data = $this->misc->getDatabaseAccessor();
266
267
        // Check that they've given a name and fields they want to select
268
269
        if (!strlen($_POST['formView'])) {
270
            return $this->doSetParamsCreate($this->lang['strviewneedsname']);
0 ignored issues
show
Bug introduced by
It seems like doSetParamsCreate() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

270
            return $this->/** @scrutinizer ignore-call */ doSetParamsCreate($this->lang['strviewneedsname']);
Loading history...
271
        }
272
        if (!isset($_POST['formFields']) || !count($_POST['formFields'])) {
273
            return $this->doSetParamsCreate($this->lang['strviewneedsfields']);
274
        }
275
        $selFields = '';
276
277
        $tmpHsh = [];
278
279
        foreach ($_POST['formFields'] as $curField) {
280
            $arrTmp = unserialize($curField);
281
            $data->fieldArrayClean($arrTmp);
282
283
            $this->_appendToSelFields($arrTmp, $selFields, $tmpHsh);
284
        }
285
286
        $selFields = substr($selFields, 0, -2);
287
        unset($arrTmp, $tmpHsh);
288
        $linkFields  = '';
289
        $arrJoined   = [];
290
        $arrUsedTbls = [];
291
292
        list($arrLinks, $count) = $this->_getArrLinks();
293
294
        // If we have at least one join condition, output it
295
296
        $j = 0;
297
298
        while ($j < $count) {
299
            foreach ($arrLinks as $curLink) {
300
                $arrLeftLink  = unserialize($curLink['leftlink']);
301
                $arrRightLink = unserialize($curLink['rightlink']);
302
                $data->fieldArrayClean($arrLeftLink);
303
                $data->fieldArrayClean($arrRightLink);
304
305
                $tbl1 = "\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\"";
306
                $tbl2 = "\"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\"";
307
308
                if (!((!in_array($curLink, $arrJoined, true) && in_array($tbl1, $arrUsedTbls, true)) || !count($arrJoined))) {
309
                    continue;
310
                }
311
                // Make sure for multi-column foreign keys that we use a table alias tables joined to more than once
312
                // This can (and should be) more optimized for multi-column foreign keys
313
                $adj_tbl2 = in_array($tbl2, $arrUsedTbls, true) ? "${tbl2} AS alias_ppa_".time() : $tbl2;
314
315
                $clause1 = "{$curLink['operator']} ${adj_tbl2} ON ({$tbl1}.\"{$arrLeftLink['fieldname']}\" = {$tbl2}.\"{$arrRightLink['fieldname']}\") ";
316
                $clause2 = "${tbl1} {$curLink['operator']} ${adj_tbl2} ON ({$tbl1}.\"{$arrLeftLink['fieldname']}\" = {$tbl2}.\"{$arrRightLink['fieldname']}\") ";
317
318
                $linkFields .= strlen($linkFields) ? $clause1 : $clause2;
319
320
                $arrJoined[] = $curLink;
321
                if (!in_array($tbl1, $arrUsedTbls, true)) {
322
                    $arrUsedTbls[] = $tbl1;
323
                }
324
325
                if (!in_array($tbl2, $arrUsedTbls, true)) {
326
                    $arrUsedTbls[] = $tbl2;
327
                }
328
            }
329
            ++$j;
330
        }
331
332
        //if linkFields has no length then either _POST['formLink'] was not set, or there were no join conditions
333
        //just select from all seleted tables - a cartesian join do a
334
        if (!strlen($linkFields)) {
335
            foreach ($_POST['formTables'] as $curTable) {
336
                $arrTmp = unserialize($curTable);
337
                $data->fieldArrayClean($arrTmp);
338
                $linkFields .= (strlen($linkFields) ? ', ' : ' ')."\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\"";
339
            }
340
        }
341
342
        $addConditions = '';
343
        if (is_array($_POST['formCondition'])) {
344
            foreach ($_POST['formCondition'] as $curCondition) {
345
                if (strlen($curCondition['field']) && strlen($curCondition['txt'])) {
346
                    $arrTmp = unserialize($curCondition['field']);
347
                    $data->fieldArrayClean($arrTmp);
348
                    $condition = " \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" {$curCondition['operator']} '{$curCondition['txt']}' ";
349
                    $addConditions .= (strlen($addConditions) ? ' AND ' : ' ').$condition;
350
                }
351
            }
352
        }
353
354
        $viewQuery = "SELECT ${selFields} FROM ${linkFields} ";
355
356
        //add where from additional conditions
357
        if (strlen($addConditions)) {
358
            $viewQuery .= ' WHERE '.$addConditions;
359
        }
360
361
        try {
362
            $status = $data->createView($_POST['formView'], $viewQuery, false, $_POST['formComment'], $is_materialized);
363
            if (0 == $status) {
364
                $this->misc->setReloadBrowser(true);
365
366
                return $this->doDefault($this->lang['strviewcreated']);
1 ignored issue
show
Bug introduced by
It seems like doDefault() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

366
                return $this->/** @scrutinizer ignore-call */ doDefault($this->lang['strviewcreated']);
Loading history...
367
            }
368
369
            return $this->doSetParamsCreate($this->lang['strviewcreatedbad']);
370
        } catch (\PHPPgAdmin\ADOdbException $e) {
371
            return $this->halt($e->getMessage());
1 ignored issue
show
Bug introduced by
It seems like halt() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

371
            return $this->/** @scrutinizer ignore-call */ halt($e->getMessage());
Loading history...
372
        }
373
    }
374
}
375