Passed
Push — develop ( 19961b...779af6 )
by Felipe
04:58
created

ViewsMatviewsTrait   B

Complexity

Total Complexity 51

Size/Duplication

Total Lines 337
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 51
dl 0
loc 337
rs 8.3206
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
B doSubTree() 0 26 1
D doSelectRows() 0 118 14
F doSaveCreateWiz() 0 136 34
B printWizardCreateForm() 0 29 2

How to fix   Complexity   

Complex Class

Complex classes like ViewsMatviewsTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ViewsMatviewsTrait, and based on these observations, apply Extract Interface, too.

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
     * Actually creates the new wizard view in the database.
210
     *
211
     * @param bool $is_materialized true if it's a materialized view, false by default
212
     *
213
     * @return mixed either a sucess message, a redirection, an error message and who knows
214
     */
215
    public function doSaveCreateWiz($is_materialized = false)
216
    {
217
        $data = $this->misc->getDatabaseAccessor();
218
219
        // Check that they've given a name and fields they want to select
220
221
        if (!strlen($_POST['formView'])) {
222
            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

222
            return $this->/** @scrutinizer ignore-call */ doSetParamsCreate($this->lang['strviewneedsname']);
Loading history...
223
        }
224
        if (!isset($_POST['formFields']) || !count($_POST['formFields'])) {
225
            return $this->doSetParamsCreate($this->lang['strviewneedsfields']);
226
        }
227
        $selFields = '';
228
229
        if (!empty($_POST['dblFldMeth'])) {
230
            $tmpHsh = [];
231
        }
232
233
        foreach ($_POST['formFields'] as $curField) {
234
            $arrTmp = unserialize($curField);
235
            $data->fieldArrayClean($arrTmp);
236
            $field_arr = [$arrTmp['schemaname'], $arrTmp['tablename'], $arrTmp['fieldname']];
237
238
            $field_element = '"'.implode('"."', $field_arr).'"';
239
            if (empty($_POST['dblFldMeth'])) {
240
                // no doublon control
241
                $selFields .= $field_element.', ';
242
            // doublon control
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 16 spaces, found 12
Loading history...
243
            } elseif (empty($tmpHsh[$arrTmp['fieldname']])) {
244
                // field does not exist
245
                $selFields .= $field_element.', ';
246
                $tmpHsh[$arrTmp['fieldname']] = 1;
247
            } elseif ('rename' == $_POST['dblFldMeth']) {
248
                // field exist and must be renamed
249
                ++$tmpHsh[$arrTmp['fieldname']];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tmpHsh does not seem to be defined for all execution paths leading up to this point.
Loading history...
250
                $selFields .= $field_element.'  AS  "'.implode('_', $field_arr).'_'.$tmpHsh[$arrTmp['fieldname']].'", ';
251
            } //  field already exist, just ignore this one
252
        }
253
254
        $selFields = substr($selFields, 0, -2);
255
        unset($arrTmp, $tmpHsh);
256
        $linkFields = '';
257
        $count      = 0;
258
259
        // If we have links, out put the JOIN ... ON statements
260
        if (is_array($_POST['formLink'])) {
261
            // Filter out invalid/blank entries for our links
262
            $arrLinks = [];
263
            foreach ($_POST['formLink'] as $curLink) {
264
                if (strlen($curLink['leftlink']) && strlen($curLink['rightlink']) && strlen($curLink['operator'])) {
265
                    $arrLinks[] = $curLink;
266
                }
267
            }
268
            // We must perform some magic to make sure that we have a valid join order
269
            $count       = sizeof($arrLinks);
270
            $arrJoined   = [];
271
            $arrUsedTbls = [];
272
        }
273
        // If we have at least one join condition, output it
274
275
        $j = 0;
276
        $this->prtrace('arrLinks ', $arrLinks);
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $arrLinks does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug introduced by
It seems like prtrace() 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

276
        $this->/** @scrutinizer ignore-call */ 
277
               prtrace('arrLinks ', $arrLinks);
Loading history...
277
        while ($j < $count) {
278
            foreach ($arrLinks as $curLink) {
279
                $arrLeftLink  = unserialize($curLink['leftlink']);
280
                $arrRightLink = unserialize($curLink['rightlink']);
281
                $data->fieldArrayClean($arrLeftLink);
282
                $data->fieldArrayClean($arrRightLink);
283
284
                $tbl1 = "\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\"";
285
                $tbl2 = "\"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\"";
286
287
                if (!((!in_array($curLink, $arrJoined, true) && in_array($tbl1, $arrUsedTbls, true)) || !count($arrJoined))) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $arrUsedTbls does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $arrJoined does not seem to be defined for all execution paths leading up to this point.
Loading history...
288
                    continue;
289
                }
290
                // Make sure for multi-column foreign keys that we use a table alias tables joined to more than once
291
                // This can (and should be) more optimized for multi-column foreign keys
292
                $adj_tbl2 = in_array($tbl2, $arrUsedTbls, true) ? "${tbl2} AS alias_ppa_".time() : $tbl2;
293
294
                $clause1 = "{$curLink['operator']} ${adj_tbl2} ON ({$tbl1}.\"{$arrLeftLink['fieldname']}\" = {$tbl2}.\"{$arrRightLink['fieldname']}\") ";
295
                $clause2 = "${tbl1} {$curLink['operator']} ${adj_tbl2} ON ({$tbl1}.\"{$arrLeftLink['fieldname']}\" = {$tbl2}.\"{$arrRightLink['fieldname']}\") ";
296
297
                $linkFields .= strlen($linkFields) ? $clause1 : $clause2;
298
299
                $arrJoined[] = $curLink;
300
                if (!in_array($tbl1, $arrUsedTbls, true)) {
301
                    $arrUsedTbls[] = $tbl1;
302
                }
303
304
                if (!in_array($tbl2, $arrUsedTbls, true)) {
305
                    $arrUsedTbls[] = $tbl2;
306
                }
307
            }
308
            ++$j;
309
        }
310
311
        //if linkFields has no length then either _POST['formLink'] was not set, or there were no join conditions
312
        //just select from all seleted tables - a cartesian join do a
313
        if (!strlen($linkFields)) {
314
            foreach ($_POST['formTables'] as $curTable) {
315
                $arrTmp = unserialize($curTable);
316
                $data->fieldArrayClean($arrTmp);
317
                $linkFields .= (strlen($linkFields) ? ', ' : ' ')."\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\"";
318
            }
319
        }
320
321
        $addConditions = '';
322
        if (is_array($_POST['formCondition'])) {
323
            foreach ($_POST['formCondition'] as $curCondition) {
324
                if (strlen($curCondition['field']) && strlen($curCondition['txt'])) {
325
                    $arrTmp = unserialize($curCondition['field']);
326
                    $data->fieldArrayClean($arrTmp);
327
                    $condition = " \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" {$curCondition['operator']} '{$curCondition['txt']}' ";
328
                    $addConditions .= (strlen($addConditions) ? ' AND ' : ' ').$condition;
329
                }
330
            }
331
        }
332
333
        $viewQuery = "SELECT ${selFields} FROM ${linkFields} ";
334
335
        //add where from additional conditions
336
        if (strlen($addConditions)) {
337
            $viewQuery .= ' WHERE '.$addConditions;
338
        }
339
340
        try {
341
            $status = $data->createView($_POST['formView'], $viewQuery, false, $_POST['formComment'], $is_materialized);
342
            if (0 == $status) {
343
                $this->misc->setReloadBrowser(true);
344
345
                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

345
                return $this->/** @scrutinizer ignore-call */ doDefault($this->lang['strviewcreated']);
Loading history...
346
            }
347
348
            return $this->doSetParamsCreate($this->lang['strviewcreatedbad']);
349
        } catch (\PHPPgAdmin\ADOdbException $e) {
350
            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

350
            return $this->/** @scrutinizer ignore-call */ halt($e->getMessage());
Loading history...
351
        }
352
    }
353
}
354