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

ViewsMatViewsPropertiesTrait::doTree()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 37
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 22
nc 1
nop 0
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 ViewsMatViewsPropertiesTrait
15
{
16
    public $href = '';
17
    public $misc;
18
    public $view_name;
19
20
    /**
21
     * Show view definition and virtual columns.
22
     *
23
     * @param mixed $msg
24
     */
25
    public function doDefault($msg = '')
26
    {
27
        $data = $this->misc->getDatabaseAccessor();
28
29
        $attPre = function (&$rowdata) use ($data) {
30
            $rowdata->fields['+type'] = $data->formatType($rowdata->fields['type'], $rowdata->fields['atttypmod']);
31
        };
32
33
        $this->printTrail($this->subject);
34
        $this->printTabs($this->subject, 'columns');
35
        $this->printMsg($msg);
36
37
        // Get view
38
        $vdata = $data->getView($_REQUEST[$this->subject]);
39
        // Get columns (using same method for getting a view)
40
        $attrs = $data->getTableAttributes($_REQUEST[$this->subject]);
41
42
        // Show comment if any
43
        if (null !== $vdata->fields['relcomment']) {
44
            echo '<p class="comment">', $this->misc->printVal($vdata->fields['relcomment']), "</p>\n";
45
        }
46
47
        $columns = [
48
            'column'  => [
49
                'title' => $this->lang['strcolumn'],
50
                'field' => Decorator::field('attname'),
51
                'url'   => "colproperties?subject=column&amp;{$this->misc->href}&amp;view=".urlencode($_REQUEST[$this->subject]).'&amp;',
52
                'vars'  => ['column' => 'attname'],
53
            ],
54
            'type'    => [
55
                'title' => $this->lang['strtype'],
56
                'field' => Decorator::field('+type'),
57
            ],
58
            'default' => [
59
                'title' => $this->lang['strdefault'],
60
                'field' => Decorator::field('adsrc'),
61
            ],
62
            'actions' => [
63
                'title' => $this->lang['stractions'],
64
            ],
65
            'comment' => [
66
                'title' => $this->lang['strcomment'],
67
                'field' => Decorator::field('comment'),
68
            ],
69
        ];
70
71
        $actions = [
72
            'alter' => [
73
                'content' => $this->lang['stralter'],
74
                'attr'    => [
75
                    'href' => [
76
                        'url'     => $this->view_name,
77
                        'urlvars' => [
78
                            'action'       => 'properties',
79
                            $this->subject => $_REQUEST[$this->subject],
80
                            'column'       => Decorator::field('attname'),
81
                        ],
82
                    ],
83
                ],
84
            ],
85
        ];
86
87
        echo $this->printTable($attrs, $columns, $actions, "{$this->view_name}-{$this->view_name}", null, $attPre);
88
89
        echo "<br />\n";
90
91
        $navlinks = [
92
            'browse' => [
93
                'attr'    => [
94
                    'href' => [
95
                        'url'     => 'display',
96
                        'urlvars' => [
97
                            'server'       => $_REQUEST['server'],
98
                            'database'     => $_REQUEST['database'],
99
                            'schema'       => $_REQUEST['schema'],
100
                            $this->subject => $_REQUEST[$this->subject],
101
                            'subject'      => $this->subject,
102
                            'return'       => $this->subject,
103
                        ],
104
                    ],
105
                ],
106
                'content' => $this->lang['strbrowse'],
107
            ],
108
            'select' => [
109
                'attr'    => [
110
                    'href' => [
111
                        'url'     => str_replace('properties', 's', $this->view_name),
112
                        'urlvars' => [
113
                            'action'       => 'confselectrows',
114
                            'server'       => $_REQUEST['server'],
115
                            'database'     => $_REQUEST['database'],
116
                            'schema'       => $_REQUEST['schema'],
117
                            $this->subject => $_REQUEST[$this->subject],
118
                        ],
119
                    ],
120
                ],
121
                'content' => $this->lang['strselect'],
122
            ],
123
            'drop'   => [
124
                'attr'    => [
125
                    'href' => [
126
                        'url'     => str_replace('properties', 's', $this->view_name),
127
                        'urlvars' => [
128
                            'action'       => 'confirm_drop',
129
                            'server'       => $_REQUEST['server'],
130
                            'database'     => $_REQUEST['database'],
131
                            'schema'       => $_REQUEST['schema'],
132
                            $this->subject => $_REQUEST[$this->subject],
133
                        ],
134
                    ],
135
                ],
136
                'content' => $this->lang['strdrop'],
137
            ],
138
            'alter'  => [
139
                'attr'    => [
140
                    'href' => [
141
                        'url'     => $this->view_name,
142
                        'urlvars' => [
143
                            'action'       => 'confirm_alter',
144
                            'server'       => $_REQUEST['server'],
145
                            'database'     => $_REQUEST['database'],
146
                            'schema'       => $_REQUEST['schema'],
147
                            $this->subject => $_REQUEST[$this->subject],
148
                        ],
149
                    ],
150
                ],
151
                'content' => $this->lang['stralter'],
152
            ],
153
        ];
154
        $this->prtrace($this->view_name);
155
        if ($this->view_name === 'materializedviewproperties') {
156
            $navlinks['refresh'] = [
157
                'attr'    => [
158
                    'href' => [
159
                        'url'     => $this->view_name,
160
                        'urlvars' => [
161
                            'action'       => 'refresh',
162
                            'server'       => $_REQUEST['server'],
163
                            'database'     => $_REQUEST['database'],
164
                            'schema'       => $_REQUEST['schema'],
165
                            $this->subject => $_REQUEST[$this->subject],
166
                        ],
167
                    ],
168
                ],
169
                'content' => $this->lang['strrefresh'],
170
            ];
171
        }
172
173
        $this->printNavLinks($navlinks, "{$this->view_name}-{$this->view_name}", get_defined_vars());
174
    }
175
176
    public function doTree()
177
    {
178
        $data = $this->misc->getDatabaseAccessor();
179
180
        $reqvars = $this->misc->getRequestVars('column');
181
        $columns = $data->getTableAttributes($_REQUEST[$this->subject]);
182
183
        $attrs = [
184
            'text'       => Decorator::field('attname'),
185
            'action'     => Decorator::actionurl(
186
                'colproperties',
187
                $reqvars,
188
                [
189
                    $this->subject => $_REQUEST[$this->subject],
190
                    'column'       => Decorator::field('attname'),
191
                ]
192
            ),
193
            'icon'       => 'Column',
194
            'iconAction' => Decorator::url(
195
                'display',
196
                $reqvars,
197
                [
198
                    $this->subject => $_REQUEST[$this->subject],
199
                    'column'       => Decorator::field('attname'),
200
                    'query'        => Decorator::replace(
201
                        'SELECT "%column%", count(*) AS "count" FROM %view% GROUP BY "%column%" ORDER BY "%column%"',
202
                        [
203
                            '%column%' => Decorator::field('attname'),
204
                            '%view%'   => $_REQUEST[$this->subject],
205
                        ]
206
                    ),
207
                ]
208
            ),
209
            'toolTip'    => Decorator::field('comment'),
210
        ];
211
212
        return $this->printTree($columns, $attrs, 'viewcolumns');
213
    }
214
215
    /**
216
     * Allow the dumping of the data "in" a view
217
     * NOTE:: PostgreSQL doesn't currently support dumping the data in a view
218
     *        so I have disabled the data related parts for now. In the future
219
     *        we should allow it conditionally if it becomes supported.  This is
220
     *        a SMOP since it is based on pg_dump version not backend version.
221
     *
222
     * @param mixed $msg
223
     */
224
    public function doExport($msg = '')
225
    {
226
        $this->printTrail($this->subject);
227
        $this->printTabs($this->subject, 'export');
228
        $this->printMsg($msg);
229
230
        $subject = $this->subject;
231
        $object  = $_REQUEST[$this->subject];
232
233
        echo $this->formHeader();
234
        // Data only
235
        // echo $this->dataOnly(false);
236
237
        // Structure only
238
        echo $this->structureOnly(true);
239
240
        // Structure and data
241
        // echo $this->structureAndData();
242
243
        echo $this->displayOrDownload();
244
245
        echo $this->formFooter($subject, $object);
246
    }
247
248
    /**
249
     * Show definition for a view or matview.
250
     *
251
     * @param mixed $msg
252
     */
253
    public function doDefinition($msg = '')
254
    {
255
        $data = $this->misc->getDatabaseAccessor();
256
257
        // Get view
258
        $vdata = $data->getView($_REQUEST[$this->subject]);
259
260
        $this->printTrail($this->subject);
261
        $this->printTabs($this->subject, 'definition');
262
        $this->printMsg($msg);
263
264
        if ($vdata->RecordCount() > 0) {
265
            // Show comment if any
266
            if (null !== $vdata->fields['relcomment']) {
267
                echo '<p class="comment">', $this->misc->printVal($vdata->fields['relcomment']), "</p>\n";
268
            }
269
270
            echo "<table style=\"width: 100%\">\n";
271
            echo "<tr><th class=\"data\">{$this->lang['strdefinition']}</th></tr>\n";
272
            echo '<tr><td class="data1">', $this->misc->printVal($vdata->fields['vwdefinition']), "</td></tr>\n";
273
            echo "</table>\n";
274
        } else {
275
            echo "<p>{$this->lang['strnodata']}</p>\n";
276
        }
277
278
        $this->printNavLinks(['alter' => [
279
            'attr'    => [
280
                'href' => [
281
                    'url'     => $this->view_name,
282
                    'urlvars' => [
283
                        'action'       => 'edit',
284
                        'server'       => $_REQUEST['server'],
285
                        'database'     => $_REQUEST['database'],
286
                        'schema'       => $_REQUEST['schema'],
287
                        $this->subject => $_REQUEST[$this->subject],
288
                    ],
289
                ],
290
            ],
291
            'content' => $this->lang['stralter'],
292
        ]], "{$this->view_name}-definition", get_defined_vars());
293
    }
294
295
    /**
296
     * Actually creates the new wizard view in the database.
297
     *
298
     * @param bool $is_materialized true if it's a materialized view, false by default
299
     *
300
     * @return mixed either a sucess message, a redirection, an error message and who knows
301
     */
302
    public function doSaveCreateWiz($is_materialized = false)
303
    {
304
        $data = $this->misc->getDatabaseAccessor();
305
306
        // Check that they've given a name and fields they want to select
307
308
        if (!strlen($_POST['formView'])) {
309
            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

309
            return $this->/** @scrutinizer ignore-call */ doSetParamsCreate($this->lang['strviewneedsname']);
Loading history...
310
        }
311
        if (!isset($_POST['formFields']) || !count($_POST['formFields'])) {
312
            return $this->doSetParamsCreate($this->lang['strviewneedsfields']);
313
        }
314
        $selFields = '';
315
316
        if (!empty($_POST['dblFldMeth'])) {
317
            $tmpHsh = [];
318
        }
319
320
        foreach ($_POST['formFields'] as $curField) {
321
            $arrTmp = unserialize($curField);
322
            $data->fieldArrayClean($arrTmp);
323
            $field_arr = [$arrTmp['schemaname'], $arrTmp['tablename'], $arrTmp['fieldname']];
324
325
            $field_element = '"'.implode('"."', $field_arr).'"';
326
            if (empty($_POST['dblFldMeth'])) {
327
                // no doublon control
328
                $selFields .= $field_element.', ';
329
            // doublon control
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected at least 16 spaces, found 12
Loading history...
330
            } elseif (empty($tmpHsh[$arrTmp['fieldname']])) {
331
                // field does not exist
332
                $selFields .= $field_element.', ';
333
                $tmpHsh[$arrTmp['fieldname']] = 1;
334
            } elseif ('rename' == $_POST['dblFldMeth']) {
335
                // field exist and must be renamed
336
                ++$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...
337
                $selFields .= $field_element.'  AS  "'.implode('_', $field_arr).'_'.$tmpHsh[$arrTmp['fieldname']].'", ';
338
            } //  field already exist, just ignore this one
339
        }
340
341
        $selFields = substr($selFields, 0, -2);
342
        unset($arrTmp, $tmpHsh);
343
        $linkFields = '';
344
        $count      = 0;
345
346
        // If we have links, out put the JOIN ... ON statements
347
        if (is_array($_POST['formLink'])) {
348
            // Filter out invalid/blank entries for our links
349
            $arrLinks = [];
350
            foreach ($_POST['formLink'] as $curLink) {
351
                if (strlen($curLink['leftlink']) && strlen($curLink['rightlink']) && strlen($curLink['operator'])) {
352
                    $arrLinks[] = $curLink;
353
                }
354
            }
355
            // We must perform some magic to make sure that we have a valid join order
356
            $count       = sizeof($arrLinks);
357
            $arrJoined   = [];
358
            $arrUsedTbls = [];
359
        }
360
        // If we have at least one join condition, output it
361
362
        $j = 0;
363
        $this->prtrace('arrLinks ', $arrLinks);
0 ignored issues
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...
364
        while ($j < $count) {
365
            foreach ($arrLinks as $curLink) {
366
                $arrLeftLink  = unserialize($curLink['leftlink']);
367
                $arrRightLink = unserialize($curLink['rightlink']);
368
                $data->fieldArrayClean($arrLeftLink);
369
                $data->fieldArrayClean($arrRightLink);
370
371
                $tbl1 = "\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\"";
372
                $tbl2 = "\"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\"";
373
374
                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...
375
                    continue;
376
                }
377
                // Make sure for multi-column foreign keys that we use a table alias tables joined to more than once
378
                // This can (and should be) more optimized for multi-column foreign keys
379
                $adj_tbl2 = in_array($tbl2, $arrUsedTbls, true) ? "${tbl2} AS alias_ppa_".time() : $tbl2;
380
381
                $clause1 = "{$curLink['operator']} ${adj_tbl2} ON ({$tbl1}.\"{$arrLeftLink['fieldname']}\" = {$tbl2}.\"{$arrRightLink['fieldname']}\") ";
382
                $clause2 = "${tbl1} {$curLink['operator']} ${adj_tbl2} ON ({$tbl1}.\"{$arrLeftLink['fieldname']}\" = {$tbl2}.\"{$arrRightLink['fieldname']}\") ";
383
384
                $linkFields .= strlen($linkFields) ? $clause1 : $clause2;
385
386
                $arrJoined[] = $curLink;
387
                if (!in_array($tbl1, $arrUsedTbls, true)) {
388
                    $arrUsedTbls[] = $tbl1;
389
                }
390
391
                if (!in_array($tbl2, $arrUsedTbls, true)) {
392
                    $arrUsedTbls[] = $tbl2;
393
                }
394
            }
395
            ++$j;
396
        }
397
398
        //if linkFields has no length then either _POST['formLink'] was not set, or there were no join conditions
399
        //just select from all seleted tables - a cartesian join do a
400
        if (!strlen($linkFields)) {
401
            foreach ($_POST['formTables'] as $curTable) {
402
                $arrTmp = unserialize($curTable);
403
                $data->fieldArrayClean($arrTmp);
404
                $linkFields .= (strlen($linkFields) ? ', ' : ' ')."\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\"";
405
            }
406
        }
407
408
        $addConditions = '';
409
        if (is_array($_POST['formCondition'])) {
410
            foreach ($_POST['formCondition'] as $curCondition) {
411
                if (strlen($curCondition['field']) && strlen($curCondition['txt'])) {
412
                    $arrTmp = unserialize($curCondition['field']);
413
                    $data->fieldArrayClean($arrTmp);
414
                    $condition = " \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" {$curCondition['operator']} '{$curCondition['txt']}' ";
415
                    $addConditions .= (strlen($addConditions) ? ' AND ' : ' ').$condition;
416
                }
417
            }
418
        }
419
420
        $viewQuery = "SELECT ${selFields} FROM ${linkFields} ";
421
422
        //add where from additional conditions
423
        if (strlen($addConditions)) {
424
            $viewQuery .= ' WHERE '.$addConditions;
425
        }
426
427
        try {
428
            $status = $data->createView($_POST['formView'], $viewQuery, false, $_POST['formComment'], $is_materialized);
429
            if (0 == $status) {
430
                $this->misc->setReloadBrowser(true);
431
432
                return $this->doDefault($this->lang['strviewcreated']);
433
            }
434
435
            return $this->doSetParamsCreate($this->lang['strviewcreatedbad']);
436
        } catch (\PHPPgAdmin\ADOdbException $e) {
437
            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

437
            return $this->/** @scrutinizer ignore-call */ halt($e->getMessage());
Loading history...
438
        }
439
    }
440
}
441