@@ 10-894 (lines=885) @@ | ||
7 | /** |
|
8 | * Base controller class |
|
9 | */ |
|
10 | class MaterializedviewsController extends BaseController |
|
11 | { |
|
12 | public $script = 'materializedviews.php'; |
|
13 | public $_name = 'MaterializedviewsController'; |
|
14 | public $table_place = 'matviews-matviews'; |
|
15 | ||
16 | public function render() |
|
17 | { |
|
18 | $conf = $this->conf; |
|
19 | $misc = $this->misc; |
|
20 | $lang = $this->lang; |
|
21 | $action = $this->action; |
|
22 | ||
23 | if ($action == 'tree') { |
|
24 | return $this->doTree(); |
|
25 | } elseif ($action == 'subtree') { |
|
26 | return $this->doSubTree(); |
|
27 | } |
|
28 | ||
29 | $data = $misc->getDatabaseAccessor(); |
|
30 | ||
31 | $this->printHeader('M ' . $lang['strviews']); |
|
32 | $this->printBody(); |
|
33 | ||
34 | switch ($action) { |
|
35 | case 'selectrows': |
|
36 | if (!isset($_REQUEST['cancel'])) { |
|
37 | $this->doSelectRows(false); |
|
38 | } else { |
|
39 | $this->doDefault(); |
|
40 | } |
|
41 | ||
42 | break; |
|
43 | case 'confselectrows': |
|
44 | $this->doSelectRows(true); |
|
45 | break; |
|
46 | case 'save_create_wiz': |
|
47 | if (isset($_REQUEST['cancel'])) { |
|
48 | $this->doDefault(); |
|
49 | } else { |
|
50 | $this->doSaveCreateWiz(); |
|
51 | } |
|
52 | ||
53 | break; |
|
54 | case 'wiz_create': |
|
55 | $this->doWizardCreate(); |
|
56 | break; |
|
57 | case 'set_params_create': |
|
58 | if (isset($_POST['cancel'])) { |
|
59 | $this->doDefault(); |
|
60 | } else { |
|
61 | $this->doSetParamsCreate(); |
|
62 | } |
|
63 | ||
64 | break; |
|
65 | case 'save_create': |
|
66 | if (isset($_REQUEST['cancel'])) { |
|
67 | $this->doDefault(); |
|
68 | } else { |
|
69 | $this->doSaveCreate(); |
|
70 | } |
|
71 | ||
72 | break; |
|
73 | case 'create': |
|
74 | $this->doCreate(); |
|
75 | break; |
|
76 | case 'drop': |
|
77 | if (isset($_POST['drop'])) { |
|
78 | $this->doDrop(false); |
|
79 | } else { |
|
80 | $this->doDefault(); |
|
81 | } |
|
82 | ||
83 | break; |
|
84 | case 'confirm_drop': |
|
85 | $this->doDrop(true); |
|
86 | break; |
|
87 | default: |
|
88 | $this->doDefault(); |
|
89 | break; |
|
90 | } |
|
91 | ||
92 | $this->printFooter(); |
|
93 | } |
|
94 | ||
95 | /** |
|
96 | * Show default list of views in the database |
|
97 | */ |
|
98 | public function doDefault($msg = '') |
|
99 | { |
|
100 | $conf = $this->conf; |
|
101 | $misc = $this->misc; |
|
102 | $lang = $this->lang; |
|
103 | $data = $misc->getDatabaseAccessor(); |
|
104 | ||
105 | $this->printTrail('schema'); |
|
106 | $this->printTabs('schema', 'matviews'); |
|
107 | $this->printMsg($msg); |
|
108 | ||
109 | //$matviews = $data->getViews(); |
|
110 | $matviews = $data->getMaterializedViews(); |
|
111 | ||
112 | $columns = [ |
|
113 | 'matview' => [ |
|
114 | 'title' => 'M ' . $lang['strview'], |
|
115 | 'field' => Decorator::field('relname'), |
|
116 | 'url' => SUBFOLDER . "/redirect/matview?{$misc->href}&", |
|
117 | 'vars' => ['matview' => 'relname'], |
|
118 | ], |
|
119 | 'owner' => [ |
|
120 | 'title' => $lang['strowner'], |
|
121 | 'field' => Decorator::field('relowner'), |
|
122 | ], |
|
123 | 'actions' => [ |
|
124 | 'title' => $lang['stractions'], |
|
125 | ], |
|
126 | 'comment' => [ |
|
127 | 'title' => $lang['strcomment'], |
|
128 | 'field' => Decorator::field('relcomment'), |
|
129 | ], |
|
130 | ]; |
|
131 | ||
132 | $actions = [ |
|
133 | 'multiactions' => [ |
|
134 | 'keycols' => ['matview' => 'relname'], |
|
135 | 'url' => 'materializedviews.php', |
|
136 | ], |
|
137 | 'browse' => [ |
|
138 | 'content' => $lang['strbrowse'], |
|
139 | 'attr' => [ |
|
140 | 'href' => [ |
|
141 | 'url' => 'display.php', |
|
142 | 'urlvars' => [ |
|
143 | 'action' => 'confselectrows', |
|
144 | 'subject' => 'matview', |
|
145 | 'return' => 'schema', |
|
146 | 'matview' => Decorator::field('relname'), |
|
147 | ], |
|
148 | ], |
|
149 | ], |
|
150 | ], |
|
151 | 'select' => [ |
|
152 | 'content' => $lang['strselect'], |
|
153 | 'attr' => [ |
|
154 | 'href' => [ |
|
155 | 'url' => 'materializedviews.php', |
|
156 | 'urlvars' => [ |
|
157 | 'action' => 'confselectrows', |
|
158 | 'matview' => Decorator::field('relname'), |
|
159 | ], |
|
160 | ], |
|
161 | ], |
|
162 | ], |
|
163 | ||
164 | // Insert is possible if the relevant rule for the view has been created. |
|
165 | // 'insert' => array( |
|
166 | // 'title' => $lang['strinsert'], |
|
167 | // 'url' => "materializedviews.php?action=confinsertrow&{$misc->href}&", |
|
168 | // 'vars' => array('view' => 'relname'), |
|
169 | // ), |
|
170 | ||
171 | 'alter' => [ |
|
172 | 'content' => $lang['stralter'], |
|
173 | 'attr' => [ |
|
174 | 'href' => [ |
|
175 | 'url' => 'materializedviewproperties.php', |
|
176 | 'urlvars' => [ |
|
177 | 'action' => 'confirm_alter', |
|
178 | 'matview' => Decorator::field('relname'), |
|
179 | ], |
|
180 | ], |
|
181 | ], |
|
182 | ], |
|
183 | 'drop' => [ |
|
184 | 'multiaction' => 'confirm_drop', |
|
185 | 'content' => $lang['strdrop'], |
|
186 | 'attr' => [ |
|
187 | 'href' => [ |
|
188 | 'url' => 'materializedviews.php', |
|
189 | 'urlvars' => [ |
|
190 | 'action' => 'confirm_drop', |
|
191 | 'matview' => Decorator::field('relname'), |
|
192 | ], |
|
193 | ], |
|
194 | ], |
|
195 | ], |
|
196 | ]; |
|
197 | ||
198 | echo $this->printTable($matviews, $columns, $actions, $this->table_place, $lang['strnoviews']); |
|
199 | ||
200 | $navlinks = [ |
|
201 | 'create' => [ |
|
202 | 'attr' => [ |
|
203 | 'href' => [ |
|
204 | 'url' => 'materializedviews.php', |
|
205 | 'urlvars' => [ |
|
206 | 'action' => 'create', |
|
207 | 'server' => $_REQUEST['server'], |
|
208 | 'database' => $_REQUEST['database'], |
|
209 | 'schema' => $_REQUEST['schema'], |
|
210 | ], |
|
211 | ], |
|
212 | ], |
|
213 | 'content' => $lang['strcreateview'], |
|
214 | ], |
|
215 | 'createwiz' => [ |
|
216 | 'attr' => [ |
|
217 | 'href' => [ |
|
218 | 'url' => 'materializedviews.php', |
|
219 | 'urlvars' => [ |
|
220 | 'action' => 'wiz_create', |
|
221 | 'server' => $_REQUEST['server'], |
|
222 | 'database' => $_REQUEST['database'], |
|
223 | 'schema' => $_REQUEST['schema'], |
|
224 | ], |
|
225 | ], |
|
226 | ], |
|
227 | 'content' => $lang['strcreateviewwiz'], |
|
228 | ], |
|
229 | ]; |
|
230 | $this->printNavLinks($navlinks, $this->table_place, get_defined_vars()); |
|
231 | } |
|
232 | ||
233 | /** |
|
234 | * Generate XML for the browser tree. |
|
235 | */ |
|
236 | public function doTree() |
|
237 | { |
|
238 | $conf = $this->conf; |
|
239 | $misc = $this->misc; |
|
240 | $lang = $this->lang; |
|
241 | $data = $misc->getDatabaseAccessor(); |
|
242 | ||
243 | $matviews = $data->getMaterializedViews(); |
|
244 | ||
245 | $reqvars = $misc->getRequestVars('matview'); |
|
246 | ||
247 | $attrs = [ |
|
248 | 'text' => Decorator::field('relname'), |
|
249 | 'icon' => 'MView', |
|
250 | 'iconAction' => Decorator::url('display.php', $reqvars, ['matview' => Decorator::field('relname')]), |
|
251 | 'toolTip' => Decorator::field('relcomment'), |
|
252 | 'action' => Decorator::redirecturl('redirect.php', $reqvars, ['matview' => Decorator::field('relname')]), |
|
253 | 'branch' => Decorator::url('materializedviews.php', $reqvars, ['action' => 'subtree', 'matview' => Decorator::field('relname')]), |
|
254 | ]; |
|
255 | ||
256 | return $this->printTree($matviews, $attrs, 'matviews'); |
|
257 | } |
|
258 | ||
259 | public function doSubTree() |
|
260 | { |
|
261 | $conf = $this->conf; |
|
262 | $misc = $this->misc; |
|
263 | $lang = $this->lang; |
|
264 | $data = $misc->getDatabaseAccessor(); |
|
265 | ||
266 | $tabs = $misc->getNavTabs('matview'); |
|
267 | $items = $this->adjustTabsForTree($tabs); |
|
268 | $reqvars = $misc->getRequestVars('matview'); |
|
269 | ||
270 | $attrs = [ |
|
271 | 'text' => Decorator::field('title'), |
|
272 | 'icon' => Decorator::field('icon'), |
|
273 | 'action' => Decorator::actionurl(Decorator::field('url'), $reqvars, Decorator::field('urlvars'), ['matview' => $_REQUEST['matview']]), |
|
274 | 'branch' => Decorator::ifempty( |
|
275 | Decorator::field('branch'), '', Decorator::url(Decorator::field('url'), Decorator::field('urlvars'), $reqvars, |
|
276 | [ |
|
277 | 'action' => 'tree', |
|
278 | 'matview' => $_REQUEST['matview'], |
|
279 | ] |
|
280 | ) |
|
281 | ), |
|
282 | ]; |
|
283 | ||
284 | return $this->printTree($items, $attrs, 'matviews'); |
|
285 | } |
|
286 | ||
287 | /** |
|
288 | * Ask for select parameters and perform select |
|
289 | */ |
|
290 | public function doSelectRows($confirm, $msg = '') |
|
291 | { |
|
292 | $conf = $this->conf; |
|
293 | $misc = $this->misc; |
|
294 | $lang = $this->lang; |
|
295 | $data = $misc->getDatabaseAccessor(); |
|
296 | ||
297 | if ($confirm) { |
|
298 | $this->printTrail('view'); |
|
299 | $this->printTabs('matview', 'select'); |
|
300 | $this->printMsg($msg); |
|
301 | ||
302 | $attrs = $data->getTableAttributes($_REQUEST['matview']); |
|
303 | ||
304 | echo '<form action="' . SUBFOLDER . '/src/views/' . $this->script . '" method="post" id="selectform">'; |
|
305 | echo "\n"; |
|
306 | ||
307 | if ($attrs->recordCount() > 0) { |
|
308 | // JavaScript for select all feature |
|
309 | echo "<script type=\"text/javascript\">\n"; |
|
310 | echo "//<![CDATA[\n"; |
|
311 | echo " function selectAll() {\n"; |
|
312 | echo " for (var i=0; i<document.getElementById('selectform').elements.length; i++) {\n"; |
|
313 | echo " var e = document.getElementById('selectform').elements[i];\n"; |
|
314 | echo " if (e.name.indexOf('show') == 0) { \n "; |
|
315 | echo " e.checked = document.getElementById('selectform').selectall.checked;\n"; |
|
316 | echo " }\n"; |
|
317 | echo " }\n"; |
|
318 | echo " }\n"; |
|
319 | echo "//]]>\n"; |
|
320 | echo "</script>\n"; |
|
321 | ||
322 | echo "<table>\n"; |
|
323 | ||
324 | // Output table header |
|
325 | echo "<tr><th class=\"data\">{$lang['strshow']}</th><th class=\"data\">{$lang['strcolumn']}</th>"; |
|
326 | echo "<th class=\"data\">{$lang['strtype']}</th><th class=\"data\">{$lang['stroperator']}</th>"; |
|
327 | echo "<th class=\"data\">{$lang['strvalue']}</th></tr>"; |
|
328 | ||
329 | $i = 0; |
|
330 | while (!$attrs->EOF) { |
|
331 | $attrs->fields['attnotnull'] = $data->phpBool($attrs->fields['attnotnull']); |
|
332 | // Set up default value if there isn't one already |
|
333 | if (!isset($_REQUEST['values'][$attrs->fields['attname']])) { |
|
334 | $_REQUEST['values'][$attrs->fields['attname']] = null; |
|
335 | } |
|
336 | ||
337 | if (!isset($_REQUEST['ops'][$attrs->fields['attname']])) { |
|
338 | $_REQUEST['ops'][$attrs->fields['attname']] = null; |
|
339 | } |
|
340 | ||
341 | // Continue drawing row |
|
342 | $id = (($i % 2) == 0 ? '1' : '2'); |
|
343 | echo "<tr class=\"data{$id}\">\n"; |
|
344 | echo '<td style="white-space:nowrap;">'; |
|
345 | echo '<input type="checkbox" name="show[', htmlspecialchars($attrs->fields['attname']), ']"', |
|
346 | isset($_REQUEST['show'][$attrs->fields['attname']]) ? ' checked="checked"' : '', ' /></td>'; |
|
347 | echo '<td style="white-space:nowrap;">', $misc->printVal($attrs->fields['attname']), '</td>'; |
|
348 | echo '<td style="white-space:nowrap;">', $misc->printVal($data->formatType($attrs->fields['type'], $attrs->fields['atttypmod'])), '</td>'; |
|
349 | echo '<td style="white-space:nowrap;">'; |
|
350 | echo "<select name=\"ops[{$attrs->fields['attname']}]\">\n"; |
|
351 | foreach (array_keys($data->selectOps) as $v) { |
|
352 | echo '<option value="', htmlspecialchars($v), '"', ($v == $_REQUEST['ops'][$attrs->fields['attname']]) ? ' selected="selected"' : '', |
|
353 | '>', htmlspecialchars($v), "</option>\n"; |
|
354 | } |
|
355 | echo "</select></td>\n"; |
|
356 | echo '<td style="white-space:nowrap;">', $data->printField("values[{$attrs->fields['attname']}]", |
|
357 | $_REQUEST['values'][$attrs->fields['attname']], $attrs->fields['type']), '</td>'; |
|
358 | echo "</tr>\n"; |
|
359 | $i++; |
|
360 | $attrs->moveNext(); |
|
361 | } |
|
362 | // Select all checkbox |
|
363 | echo "<tr><td colspan=\"5\"><input type=\"checkbox\" id=\"selectall\" name=\"selectall\" accesskey=\"a\" onclick=\"javascript:selectAll()\" /><label for=\"selectall\">{$lang['strselectallfields']}</label></td></tr>"; |
|
364 | echo "</table>\n"; |
|
365 | } else { |
|
366 | echo "<p>{$lang['strinvalidparam']}</p>\n"; |
|
367 | } |
|
368 | ||
369 | echo "<p><input type=\"hidden\" name=\"action\" value=\"selectrows\" />\n"; |
|
370 | echo '<input type="hidden" name="view" value="', htmlspecialchars($_REQUEST['matview']), "\" />\n"; |
|
371 | echo "<input type=\"hidden\" name=\"subject\" value=\"view\" />\n"; |
|
372 | echo $misc->form; |
|
373 | echo "<input type=\"submit\" name=\"select\" accesskey=\"r\" value=\"{$lang['strselect']}\" />\n"; |
|
374 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; |
|
375 | echo "</form>\n"; |
|
376 | return; |
|
377 | } else { |
|
378 | if (!isset($_POST['show'])) { |
|
379 | $_POST['show'] = []; |
|
380 | } |
|
381 | ||
382 | if (!isset($_POST['values'])) { |
|
383 | $_POST['values'] = []; |
|
384 | } |
|
385 | ||
386 | if (!isset($_POST['nulls'])) { |
|
387 | $_POST['nulls'] = []; |
|
388 | } |
|
389 | ||
390 | // Verify that they haven't supplied a value for unary operators |
|
391 | foreach ($_POST['ops'] as $k => $v) { |
|
392 | if ($data->selectOps[$v] == 'p' && $_POST['values'][$k] != '') { |
|
393 | $this->doSelectRows(true, $lang['strselectunary']); |
|
394 | return; |
|
395 | } |
|
396 | } |
|
397 | ||
398 | if (sizeof($_POST['show']) == 0) { |
|
399 | return $this->doSelectRows(true, $lang['strselectneedscol']); |
|
400 | } else { |
|
401 | // Generate query SQL |
|
402 | $query = $data->getSelectSQL($_REQUEST['matview'], array_keys($_POST['show']), $_POST['values'], $_POST['ops']); |
|
403 | ||
404 | $_REQUEST['query'] = $query; |
|
405 | $_REQUEST['return'] = 'schema'; |
|
406 | ||
407 | $this->setNoOutput(true); |
|
408 | ||
409 | $display_controller = new DisplayController($this->getContainer()); |
|
410 | ||
411 | return $display_controller->render(); |
|
412 | } |
|
413 | } |
|
414 | } |
|
415 | ||
416 | /** |
|
417 | * Show confirmation of drop and perform actual drop |
|
418 | */ |
|
419 | public function doDrop($confirm) |
|
420 | { |
|
421 | $conf = $this->conf; |
|
422 | $misc = $this->misc; |
|
423 | $lang = $this->lang; |
|
424 | $data = $misc->getDatabaseAccessor(); |
|
425 | ||
426 | if (empty($_REQUEST['matview']) && empty($_REQUEST['ma'])) { |
|
427 | $this->doDefault($lang['strspecifyviewtodrop']); |
|
428 | exit(); |
|
429 | } |
|
430 | ||
431 | if ($confirm) { |
|
432 | $this->printTrail('getTrail'); |
|
433 | $this->printTitle($lang['strdrop'], 'pg.matview.drop'); |
|
434 | ||
435 | echo '<form action="' . SUBFOLDER . "/src/views/materializedviews.php\" method=\"post\">\n"; |
|
436 | ||
437 | //If multi drop |
|
438 | if (isset($_REQUEST['ma'])) { |
|
439 | foreach ($_REQUEST['ma'] as $v) { |
|
440 | $a = unserialize(htmlspecialchars_decode($v, ENT_QUOTES)); |
|
441 | echo '<p>', sprintf($lang['strconfdropview'], $misc->printVal($a['view'])), "</p>\n"; |
|
442 | echo '<input type="hidden" name="view[]" value="', htmlspecialchars($a['view']), "\" />\n"; |
|
443 | } |
|
444 | } else { |
|
445 | echo '<p>', sprintf($lang['strconfdropview'], $misc->printVal($_REQUEST['matview'])), "</p>\n"; |
|
446 | echo '<input type="hidden" name="view" value="', htmlspecialchars($_REQUEST['matview']), "\" />\n"; |
|
447 | } |
|
448 | ||
449 | echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n"; |
|
450 | ||
451 | echo $misc->form; |
|
452 | echo "<p><input type=\"checkbox\" id=\"cascade\" name=\"cascade\" /> <label for=\"cascade\">{$lang['strcascade']}</label></p>\n"; |
|
453 | echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n"; |
|
454 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />\n"; |
|
455 | echo "</form>\n"; |
|
456 | } else { |
|
457 | if (is_array($_POST['view'])) { |
|
458 | $msg = ''; |
|
459 | $status = $data->beginTransaction(); |
|
460 | if ($status == 0) { |
|
461 | foreach ($_POST['view'] as $s) { |
|
462 | $status = $data->dropView($s, isset($_POST['cascade'])); |
|
463 | if ($status == 0) { |
|
464 | $msg .= sprintf('%s: %s<br />', htmlentities($s, ENT_QUOTES, 'UTF-8'), $lang['strviewdropped']); |
|
465 | } else { |
|
466 | $data->endTransaction(); |
|
467 | $this->doDefault(sprintf('%s%s: %s<br />', $msg, htmlentities($s, ENT_QUOTES, 'UTF-8'), $lang['strviewdroppedbad'])); |
|
468 | return; |
|
469 | } |
|
470 | } |
|
471 | } |
|
472 | if ($data->endTransaction() == 0) { |
|
473 | // Everything went fine, back to the Default page.... |
|
474 | $this->misc->setReloadBrowser(true); |
|
475 | $this->doDefault($msg); |
|
476 | } else { |
|
477 | $this->doDefault($lang['strviewdroppedbad']); |
|
478 | } |
|
479 | } else { |
|
480 | $status = $data->dropView($_POST['view'], isset($_POST['cascade'])); |
|
481 | if ($status == 0) { |
|
482 | $this->misc->setReloadBrowser(true); |
|
483 | $this->doDefault($lang['strviewdropped']); |
|
484 | } else { |
|
485 | $this->doDefault($lang['strviewdroppedbad']); |
|
486 | } |
|
487 | } |
|
488 | } |
|
489 | } |
|
490 | ||
491 | /** |
|
492 | * Sets up choices for table linkage, and which fields to select for the view we're creating |
|
493 | */ |
|
494 | public function doSetParamsCreate($msg = '') |
|
495 | { |
|
496 | $conf = $this->conf; |
|
497 | $misc = $this->misc; |
|
498 | $lang = $this->lang; |
|
499 | $data = $misc->getDatabaseAccessor(); |
|
500 | ||
501 | // Check that they've chosen tables for the view definition |
|
502 | if (!isset($_POST['formTables'])) { |
|
503 | $this->doWizardCreate($lang['strviewneedsdef']); |
|
504 | } else { |
|
505 | // Initialise variables |
|
506 | if (!isset($_REQUEST['formView'])) { |
|
507 | $_REQUEST['formView'] = ''; |
|
508 | } |
|
509 | ||
510 | if (!isset($_REQUEST['formComment'])) { |
|
511 | $_REQUEST['formComment'] = ''; |
|
512 | } |
|
513 | ||
514 | $this->printTrail('schema'); |
|
515 | $this->printTitle($lang['strcreateviewwiz'], 'pg.matview.create'); |
|
516 | $this->printMsg($msg); |
|
517 | ||
518 | $tblCount = sizeof($_POST['formTables']); |
|
519 | //unserialize our schema/table information and store in arrSelTables |
|
520 | for ($i = 0; $i < $tblCount; $i++) { |
|
521 | $arrSelTables[] = unserialize($_POST['formTables'][$i]); |
|
522 | } |
|
523 | ||
524 | $linkCount = $tblCount; |
|
525 | ||
526 | //get linking keys |
|
527 | $rsLinkKeys = $data->getLinkingKeys($arrSelTables); |
|
528 | $linkCount = $rsLinkKeys->recordCount() > $tblCount ? $rsLinkKeys->recordCount() : $tblCount; |
|
529 | ||
530 | $arrFields = []; //array that will hold all our table/field names |
|
531 | ||
532 | //if we have schemas we need to specify the correct schema for each table we're retrieiving |
|
533 | //with getTableAttributes |
|
534 | $curSchema = $data->_schema; |
|
535 | for ($i = 0; $i < $tblCount; $i++) { |
|
536 | if ($data->_schema != $arrSelTables[$i]['schemaname']) { |
|
537 | $data->setSchema($arrSelTables[$i]['schemaname']); |
|
538 | } |
|
539 | ||
540 | $attrs = $data->getTableAttributes($arrSelTables[$i]['tablename']); |
|
541 | while (!$attrs->EOF) { |
|
542 | $arrFields["{$arrSelTables[$i]['schemaname']}.{$arrSelTables[$i]['tablename']}.{$attrs->fields['attname']}"] = serialize([ |
|
543 | 'schemaname' => $arrSelTables[$i]['schemaname'], |
|
544 | 'tablename' => $arrSelTables[$i]['tablename'], |
|
545 | 'fieldname' => $attrs->fields['attname']] |
|
546 | ); |
|
547 | $attrs->moveNext(); |
|
548 | } |
|
549 | ||
550 | $data->setSchema($curSchema); |
|
551 | } |
|
552 | asort($arrFields); |
|
553 | ||
554 | echo '<form action="' . SUBFOLDER . "/src/views/materializedviews.php\" method=\"post\">\n"; |
|
555 | echo "<table>\n"; |
|
556 | echo "<tr><th class=\"data\">{$lang['strviewname']}</th></tr>"; |
|
557 | echo "<tr>\n<td class=\"data1\">\n"; |
|
558 | // View name |
|
559 | echo '<input name="formView" value="', htmlspecialchars($_REQUEST['formView']), "\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" />\n"; |
|
560 | echo "</td>\n</tr>\n"; |
|
561 | echo "<tr><th class=\"data\">{$lang['strcomment']}</th></tr>"; |
|
562 | echo "<tr>\n<td class=\"data1\">\n"; |
|
563 | // View comments |
|
564 | echo '<textarea name="formComment" rows="3" cols="32">', |
|
565 | htmlspecialchars($_REQUEST['formComment']), "</textarea>\n"; |
|
566 | echo "</td>\n</tr>\n"; |
|
567 | echo "</table>\n"; |
|
568 | ||
569 | // Output selector for fields to be retrieved from view |
|
570 | echo "<table>\n"; |
|
571 | echo "<tr><th class=\"data\">{$lang['strcolumns']}</th></tr>"; |
|
572 | echo "<tr>\n<td class=\"data1\">\n"; |
|
573 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, 'formFields[]', false, '', true); |
|
574 | echo "</td>\n</tr>"; |
|
575 | echo "<tr><td><input type=\"radio\" name=\"dblFldMeth\" id=\"dblFldMeth1\" value=\"rename\" /><label for=\"dblFldMeth1\">{$lang['strrenamedupfields']}</label>"; |
|
576 | echo "<br /><input type=\"radio\" name=\"dblFldMeth\" id=\"dblFldMeth2\" value=\"drop\" /><label for=\"dblFldMeth2\">{$lang['strdropdupfields']}</label>"; |
|
577 | echo "<br /><input type=\"radio\" name=\"dblFldMeth\" id=\"dblFldMeth3\" value=\"\" checked=\"checked\" /><label for=\"dblFldMeth3\">{$lang['strerrordupfields']}</label></td></tr></table><br />"; |
|
578 | ||
579 | // Output the Linking keys combo boxes |
|
580 | echo "<table>\n"; |
|
581 | echo "<tr><th class=\"data\">{$lang['strviewlink']}</th></tr>"; |
|
582 | $rowClass = 'data1'; |
|
583 | for ($i = 0; $i < $linkCount; $i++) { |
|
584 | // Initialise variables |
|
585 | if (!isset($formLink[$i]['operator'])) { |
|
586 | $formLink[$i]['operator'] = 'INNER JOIN'; |
|
587 | } |
|
588 | ||
589 | echo "<tr>\n<td class=\"$rowClass\">\n"; |
|
590 | ||
591 | if (!$rsLinkKeys->EOF) { |
|
592 | $curLeftLink = htmlspecialchars(serialize(['schemaname' => $rsLinkKeys->fields['p_schema'], 'tablename' => $rsLinkKeys->fields['p_table'], 'fieldname' => $rsLinkKeys->fields['p_field']])); |
|
593 | $curRightLink = htmlspecialchars(serialize(['schemaname' => $rsLinkKeys->fields['f_schema'], 'tablename' => $rsLinkKeys->fields['f_table'], 'fieldname' => $rsLinkKeys->fields['f_field']])); |
|
594 | $rsLinkKeys->moveNext(); |
|
595 | } else { |
|
596 | $curLeftLink = ''; |
|
597 | $curRightLink = ''; |
|
598 | } |
|
599 | ||
600 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, "formLink[$i][leftlink]", true, $curLeftLink, false); |
|
601 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($data->joinOps, "formLink[$i][operator]", true, $formLink[$i]['operator']); |
|
602 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, "formLink[$i][rightlink]", true, $curRightLink, false); |
|
603 | echo "</td>\n</tr>\n"; |
|
604 | $rowClass = $rowClass == 'data1' ? 'data2' : 'data1'; |
|
605 | } |
|
606 | echo "</table>\n<br />\n"; |
|
607 | ||
608 | // Build list of available operators (infix only) |
|
609 | $arrOperators = []; |
|
610 | foreach ($data->selectOps as $k => $v) { |
|
611 | if ($v == 'i') { |
|
612 | $arrOperators[$k] = $k; |
|
613 | } |
|
614 | } |
|
615 | ||
616 | // Output additional conditions, note that this portion of the wizard treats the right hand side as literal values |
|
617 | //(not as database objects) so field names will be treated as strings, use the above linking keys section to perform joins |
|
618 | echo "<table>\n"; |
|
619 | echo "<tr><th class=\"data\">{$lang['strviewconditions']}</th></tr>"; |
|
620 | $rowClass = 'data1'; |
|
621 | for ($i = 0; $i < $linkCount; $i++) { |
|
622 | echo "<tr>\n<td class=\"$rowClass\">\n"; |
|
623 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, "formCondition[$i][field]"); |
|
624 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrOperators, "formCondition[$i][operator]", false, false); |
|
625 | echo "<input type=\"text\" name=\"formCondition[$i][txt]\" />\n"; |
|
626 | echo "</td>\n</tr>\n"; |
|
627 | $rowClass = $rowClass == 'data1' ? 'data2' : 'data1'; |
|
628 | } |
|
629 | echo "</table>\n"; |
|
630 | echo "<p><input type=\"hidden\" name=\"action\" value=\"save_create_wiz\" />\n"; |
|
631 | ||
632 | foreach ($arrSelTables as $curTable) { |
|
633 | echo '<input type="hidden" name="formTables[]" value="' . htmlspecialchars(serialize($curTable)) . "\" />\n"; |
|
634 | } |
|
635 | ||
636 | echo $misc->form; |
|
637 | echo "<input type=\"submit\" value=\"{$lang['strcreate']}\" />\n"; |
|
638 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; |
|
639 | echo "</form>\n"; |
|
640 | } |
|
641 | } |
|
642 | ||
643 | /** |
|
644 | * Display a wizard where they can enter a new view |
|
645 | */ |
|
646 | public function doWizardCreate($msg = '') |
|
647 | { |
|
648 | $conf = $this->conf; |
|
649 | $misc = $this->misc; |
|
650 | $lang = $this->lang; |
|
651 | $data = $misc->getDatabaseAccessor(); |
|
652 | ||
653 | $tables = $data->getTables(true); |
|
654 | ||
655 | $this->printTrail('schema'); |
|
656 | $this->printTitle($lang['strcreateviewwiz'], 'pg.matview.create'); |
|
657 | $this->printMsg($msg); |
|
658 | ||
659 | echo '<form action="' . SUBFOLDER . "/src/views/materializedviews.php\" method=\"post\">\n"; |
|
660 | echo "<table>\n"; |
|
661 | echo "<tr><th class=\"data\">{$lang['strtables']}</th></tr>"; |
|
662 | echo "<tr>\n<td class=\"data1\">\n"; |
|
663 | ||
664 | $arrTables = []; |
|
665 | while (!$tables->EOF) { |
|
666 | $arrTmp = []; |
|
667 | $arrTmp['schemaname'] = $tables->fields['nspname']; |
|
668 | $arrTmp['tablename'] = $tables->fields['relname']; |
|
669 | $arrTables[$tables->fields['nspname'] . '.' . $tables->fields['relname']] = serialize($arrTmp); |
|
670 | $tables->moveNext(); |
|
671 | } |
|
672 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrTables, 'formTables[]', false, '', true); |
|
673 | ||
674 | echo "</td>\n</tr>\n"; |
|
675 | echo "</table>\n"; |
|
676 | echo "<p><input type=\"hidden\" name=\"action\" value=\"set_params_create\" />\n"; |
|
677 | echo $misc->form; |
|
678 | echo "<input type=\"submit\" value=\"{$lang['strnext']}\" />\n"; |
|
679 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; |
|
680 | echo "</form>\n"; |
|
681 | } |
|
682 | ||
683 | /** |
|
684 | * Displays a screen where they can enter a new view |
|
685 | */ |
|
686 | public function doCreate($msg = '') |
|
687 | { |
|
688 | $conf = $this->conf; |
|
689 | $misc = $this->misc; |
|
690 | $lang = $this->lang; |
|
691 | $data = $misc->getDatabaseAccessor(); |
|
692 | ||
693 | if (!isset($_REQUEST['formView'])) { |
|
694 | $_REQUEST['formView'] = ''; |
|
695 | } |
|
696 | ||
697 | if (!isset($_REQUEST['formDefinition'])) { |
|
698 | if (isset($_SESSION['sqlquery'])) { |
|
699 | $_REQUEST['formDefinition'] = $_SESSION['sqlquery']; |
|
700 | } else { |
|
701 | $_REQUEST['formDefinition'] = 'SELECT '; |
|
702 | } |
|
703 | } |
|
704 | if (!isset($_REQUEST['formComment'])) { |
|
705 | $_REQUEST['formComment'] = ''; |
|
706 | } |
|
707 | ||
708 | $this->printTrail('schema'); |
|
709 | $this->printTitle($lang['strcreateview'], 'pg.matview.create'); |
|
710 | $this->printMsg($msg); |
|
711 | ||
712 | echo '<form action="' . SUBFOLDER . "/src/views/materializedviews.php\" method=\"post\">\n"; |
|
713 | echo "<table style=\"width: 100%\">\n"; |
|
714 | echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strname']}</th>\n"; |
|
715 | echo "\t<td class=\"data1\"><input name=\"formView\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"", |
|
716 | htmlspecialchars($_REQUEST['formView']), "\" /></td>\n\t</tr>\n"; |
|
717 | echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strdefinition']}</th>\n"; |
|
718 | echo "\t<td class=\"data1\"><textarea style=\"width:100%;\" rows=\"10\" cols=\"50\" name=\"formDefinition\">", |
|
719 | htmlspecialchars($_REQUEST['formDefinition']), "</textarea></td>\n\t</tr>\n"; |
|
720 | echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strcomment']}</th>\n"; |
|
721 | echo "\t\t<td class=\"data1\"><textarea name=\"formComment\" rows=\"3\" cols=\"32\">", |
|
722 | htmlspecialchars($_REQUEST['formComment']), "</textarea></td>\n\t</tr>\n"; |
|
723 | echo "</table>\n"; |
|
724 | echo "<p><input type=\"hidden\" name=\"action\" value=\"save_create\" />\n"; |
|
725 | echo $misc->form; |
|
726 | echo "<input type=\"submit\" value=\"{$lang['strcreate']}\" />\n"; |
|
727 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; |
|
728 | echo "</form>\n"; |
|
729 | } |
|
730 | ||
731 | /** |
|
732 | * Actually creates the new view in the database |
|
733 | */ |
|
734 | public function doSaveCreate() |
|
735 | { |
|
736 | $conf = $this->conf; |
|
737 | $misc = $this->misc; |
|
738 | $lang = $this->lang; |
|
739 | $data = $misc->getDatabaseAccessor(); |
|
740 | ||
741 | // Check that they've given a name and a definition |
|
742 | if ($_POST['formView'] == '') { |
|
743 | $this->doCreate($lang['strviewneedsname']); |
|
744 | } elseif ($_POST['formDefinition'] == '') { |
|
745 | $this->doCreate($lang['strviewneedsdef']); |
|
746 | } else { |
|
747 | $status = $data->createView($_POST['formView'], $_POST['formDefinition'], false, $_POST['formComment']); |
|
748 | if ($status == 0) { |
|
749 | $this->misc->setReloadBrowser(true); |
|
750 | $this->doDefault($lang['strviewcreated']); |
|
751 | } else { |
|
752 | $this->doCreate($lang['strviewcreatedbad']); |
|
753 | } |
|
754 | } |
|
755 | } |
|
756 | ||
757 | /** |
|
758 | * Actually creates the new wizard view in the database |
|
759 | */ |
|
760 | public function doSaveCreateWiz() |
|
761 | { |
|
762 | $conf = $this->conf; |
|
763 | $misc = $this->misc; |
|
764 | $lang = $this->lang; |
|
765 | $data = $misc->getDatabaseAccessor(); |
|
766 | ||
767 | // Check that they've given a name and fields they want to select |
|
768 | ||
769 | if (!strlen($_POST['formView'])) { |
|
770 | $this->doSetParamsCreate($lang['strviewneedsname']); |
|
771 | } elseif (!isset($_POST['formFields']) || !count($_POST['formFields'])) { |
|
772 | $this->doSetParamsCreate($lang['strviewneedsfields']); |
|
773 | } else { |
|
774 | $selFields = ''; |
|
775 | ||
776 | if (!empty($_POST['dblFldMeth'])) { |
|
777 | $tmpHsh = []; |
|
778 | } |
|
779 | ||
780 | foreach ($_POST['formFields'] as $curField) { |
|
781 | $arrTmp = unserialize($curField); |
|
782 | $data->fieldArrayClean($arrTmp); |
|
783 | if (!empty($_POST['dblFldMeth'])) { |
|
784 | // doublon control |
|
785 | if (empty($tmpHsh[$arrTmp['fieldname']])) { |
|
786 | // field does not exist |
|
787 | $selFields .= "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\", "; |
|
788 | $tmpHsh[$arrTmp['fieldname']] = 1; |
|
789 | } elseif ($_POST['dblFldMeth'] == 'rename') { |
|
790 | // field exist and must be renamed |
|
791 | $tmpHsh[$arrTmp['fieldname']]++; |
|
792 | $selFields .= "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" AS \"{$arrTmp['schemaname']}_{$arrTmp['tablename']}_{$arrTmp['fieldname']}{$tmpHsh[$arrTmp['fieldname']]}\", "; |
|
793 | } |
|
794 | /* field already exist, just ignore this one */ |
|
795 | } else { |
|
796 | // no doublon control |
|
797 | $selFields .= "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\", "; |
|
798 | } |
|
799 | } |
|
800 | ||
801 | $selFields = substr($selFields, 0, -2); |
|
802 | unset($arrTmp, $tmpHsh); |
|
803 | $linkFields = ''; |
|
804 | ||
805 | // If we have links, out put the JOIN ... ON statements |
|
806 | if (is_array($_POST['formLink'])) { |
|
807 | // Filter out invalid/blank entries for our links |
|
808 | $arrLinks = []; |
|
809 | foreach ($_POST['formLink'] as $curLink) { |
|
810 | if (strlen($curLink['leftlink']) && strlen($curLink['rightlink']) && strlen($curLink['operator'])) { |
|
811 | $arrLinks[] = $curLink; |
|
812 | } |
|
813 | } |
|
814 | // We must perform some magic to make sure that we have a valid join order |
|
815 | $count = sizeof($arrLinks); |
|
816 | $arrJoined = []; |
|
817 | $arrUsedTbls = []; |
|
818 | ||
819 | // If we have at least one join condition, output it |
|
820 | if ($count > 0) { |
|
821 | $j = 0; |
|
822 | while ($j < $count) { |
|
823 | foreach ($arrLinks as $curLink) { |
|
824 | $arrLeftLink = unserialize($curLink['leftlink']); |
|
825 | $arrRightLink = unserialize($curLink['rightlink']); |
|
826 | $data->fieldArrayClean($arrLeftLink); |
|
827 | $data->fieldArrayClean($arrRightLink); |
|
828 | ||
829 | $tbl1 = "\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\""; |
|
830 | $tbl2 = "\"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\""; |
|
831 | ||
832 | if ((!in_array($curLink, $arrJoined) && in_array($tbl1, $arrUsedTbls)) || !count($arrJoined)) { |
|
833 | ||
834 | // Make sure for multi-column foreign keys that we use a table alias tables joined to more than once |
|
835 | // This can (and should be) more optimized for multi-column foreign keys |
|
836 | $adj_tbl2 = in_array($tbl2, $arrUsedTbls) ? "$tbl2 AS alias_ppa_" . mktime() : $tbl2; |
|
837 | ||
838 | $linkFields .= strlen($linkFields) ? "{$curLink['operator']} $adj_tbl2 ON (\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\".\"{$arrLeftLink['fieldname']}\" = \"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\".\"{$arrRightLink['fieldname']}\") " |
|
839 | : "$tbl1 {$curLink['operator']} $adj_tbl2 ON (\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\".\"{$arrLeftLink['fieldname']}\" = \"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\".\"{$arrRightLink['fieldname']}\") "; |
|
840 | ||
841 | $arrJoined[] = $curLink; |
|
842 | if (!in_array($tbl1, $arrUsedTbls)) { |
|
843 | $arrUsedTbls[] = $tbl1; |
|
844 | } |
|
845 | ||
846 | if (!in_array($tbl2, $arrUsedTbls)) { |
|
847 | $arrUsedTbls[] = $tbl2; |
|
848 | } |
|
849 | } |
|
850 | } |
|
851 | $j++; |
|
852 | } |
|
853 | } |
|
854 | } |
|
855 | ||
856 | //if linkfields has no length then either _POST['formLink'] was not set, or there were no join conditions |
|
857 | //just select from all seleted tables - a cartesian join do a |
|
858 | if (!strlen($linkFields)) { |
|
859 | foreach ($_POST['formTables'] as $curTable) { |
|
860 | $arrTmp = unserialize($curTable); |
|
861 | $data->fieldArrayClean($arrTmp); |
|
862 | $linkFields .= strlen($linkFields) ? ", \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\"" : "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\""; |
|
863 | } |
|
864 | } |
|
865 | ||
866 | $addConditions = ''; |
|
867 | if (is_array($_POST['formCondition'])) { |
|
868 | foreach ($_POST['formCondition'] as $curCondition) { |
|
869 | if (strlen($curCondition['field']) && strlen($curCondition['txt'])) { |
|
870 | $arrTmp = unserialize($curCondition['field']); |
|
871 | $data->fieldArrayClean($arrTmp); |
|
872 | $addConditions .= strlen($addConditions) ? " AND \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" {$curCondition['operator']} '{$curCondition['txt']}' " |
|
873 | : " \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" {$curCondition['operator']} '{$curCondition['txt']}' "; |
|
874 | } |
|
875 | } |
|
876 | } |
|
877 | ||
878 | $viewQuery = "SELECT $selFields FROM $linkFields "; |
|
879 | ||
880 | //add where from additional conditions |
|
881 | if (strlen($addConditions)) { |
|
882 | $viewQuery .= ' WHERE ' . $addConditions; |
|
883 | } |
|
884 | ||
885 | $status = $data->createView($_POST['formView'], $viewQuery, false, $_POST['formComment']); |
|
886 | if ($status == 0) { |
|
887 | $this->misc->setReloadBrowser(true); |
|
888 | $this->doDefault($lang['strviewcreated']); |
|
889 | } else { |
|
890 | $this->doSetParamsCreate($lang['strviewcreatedbad']); |
|
891 | } |
|
892 | } |
|
893 | } |
|
894 | } |
|
895 |
@@ 10-893 (lines=884) @@ | ||
7 | /** |
|
8 | * Base controller class |
|
9 | */ |
|
10 | class ViewsController extends BaseController |
|
11 | { |
|
12 | public $script = 'views.php'; |
|
13 | public $_name = 'ViewsController'; |
|
14 | public $table_place = 'views-views'; |
|
15 | ||
16 | public function render() |
|
17 | { |
|
18 | $conf = $this->conf; |
|
19 | $misc = $this->misc; |
|
20 | $lang = $this->lang; |
|
21 | $action = $this->action; |
|
22 | ||
23 | if ($action == 'tree') { |
|
24 | return $this->doTree(); |
|
25 | } elseif ($action == 'subtree') { |
|
26 | return $this->doSubTree(); |
|
27 | } |
|
28 | ||
29 | $data = $misc->getDatabaseAccessor(); |
|
30 | ||
31 | $this->printHeader($lang['strviews']); |
|
32 | $this->printBody(); |
|
33 | ||
34 | switch ($action) { |
|
35 | case 'selectrows': |
|
36 | if (!isset($_REQUEST['cancel'])) { |
|
37 | $this->doSelectRows(false); |
|
38 | } else { |
|
39 | $this->doDefault(); |
|
40 | } |
|
41 | ||
42 | break; |
|
43 | case 'confselectrows': |
|
44 | $this->doSelectRows(true); |
|
45 | break; |
|
46 | case 'save_create_wiz': |
|
47 | if (isset($_REQUEST['cancel'])) { |
|
48 | $this->doDefault(); |
|
49 | } else { |
|
50 | $this->doSaveCreateWiz(); |
|
51 | } |
|
52 | ||
53 | break; |
|
54 | case 'wiz_create': |
|
55 | $this->doWizardCreate(); |
|
56 | break; |
|
57 | case 'set_params_create': |
|
58 | if (isset($_POST['cancel'])) { |
|
59 | $this->doDefault(); |
|
60 | } else { |
|
61 | $this->doSetParamsCreate(); |
|
62 | } |
|
63 | ||
64 | break; |
|
65 | case 'save_create': |
|
66 | if (isset($_REQUEST['cancel'])) { |
|
67 | $this->doDefault(); |
|
68 | } else { |
|
69 | $this->doSaveCreate(); |
|
70 | } |
|
71 | ||
72 | break; |
|
73 | case 'create': |
|
74 | $this->doCreate(); |
|
75 | break; |
|
76 | case 'drop': |
|
77 | if (isset($_POST['drop'])) { |
|
78 | $this->doDrop(false); |
|
79 | } else { |
|
80 | $this->doDefault(); |
|
81 | } |
|
82 | ||
83 | break; |
|
84 | case 'confirm_drop': |
|
85 | $this->doDrop(true); |
|
86 | break; |
|
87 | default: |
|
88 | $this->doDefault(); |
|
89 | break; |
|
90 | } |
|
91 | ||
92 | return $this->printFooter(); |
|
93 | } |
|
94 | ||
95 | /** |
|
96 | * Show default list of views in the database |
|
97 | */ |
|
98 | public function doDefault($msg = '') |
|
99 | { |
|
100 | $conf = $this->conf; |
|
101 | $misc = $this->misc; |
|
102 | $lang = $this->lang; |
|
103 | $data = $misc->getDatabaseAccessor(); |
|
104 | ||
105 | $this->printTrail('schema'); |
|
106 | $this->printTabs('schema', 'views'); |
|
107 | $this->printMsg($msg); |
|
108 | ||
109 | $views = $data->getViews(); |
|
110 | ||
111 | $columns = [ |
|
112 | 'view' => [ |
|
113 | 'title' => $lang['strview'], |
|
114 | 'field' => Decorator::field('relname'), |
|
115 | 'url' => SUBFOLDER . "/redirect/view?{$misc->href}&", |
|
116 | 'vars' => ['view' => 'relname'], |
|
117 | ], |
|
118 | 'owner' => [ |
|
119 | 'title' => $lang['strowner'], |
|
120 | 'field' => Decorator::field('relowner'), |
|
121 | ], |
|
122 | 'actions' => [ |
|
123 | 'title' => $lang['stractions'], |
|
124 | ], |
|
125 | 'comment' => [ |
|
126 | 'title' => $lang['strcomment'], |
|
127 | 'field' => Decorator::field('relcomment'), |
|
128 | ], |
|
129 | ]; |
|
130 | ||
131 | $actions = [ |
|
132 | 'multiactions' => [ |
|
133 | 'keycols' => ['view' => 'relname'], |
|
134 | 'url' => 'views.php', |
|
135 | ], |
|
136 | 'browse' => [ |
|
137 | 'content' => $lang['strbrowse'], |
|
138 | 'attr' => [ |
|
139 | 'href' => [ |
|
140 | 'url' => 'display.php', |
|
141 | 'urlvars' => [ |
|
142 | 'action' => 'confselectrows', |
|
143 | 'subject' => 'view', |
|
144 | 'return' => 'schema', |
|
145 | 'view' => Decorator::field('relname'), |
|
146 | ], |
|
147 | ], |
|
148 | ], |
|
149 | ], |
|
150 | 'select' => [ |
|
151 | 'content' => $lang['strselect'], |
|
152 | 'attr' => [ |
|
153 | 'href' => [ |
|
154 | 'url' => 'views.php', |
|
155 | 'urlvars' => [ |
|
156 | 'action' => 'confselectrows', |
|
157 | 'view' => Decorator::field('relname'), |
|
158 | ], |
|
159 | ], |
|
160 | ], |
|
161 | ], |
|
162 | ||
163 | // Insert is possible if the relevant rule for the view has been created. |
|
164 | // 'insert' => array( |
|
165 | // 'title' => $lang['strinsert'], |
|
166 | // 'url' => "views.php?action=confinsertrow&{$misc->href}&", |
|
167 | // 'vars' => array('view' => 'relname'), |
|
168 | // ), |
|
169 | ||
170 | 'alter' => [ |
|
171 | 'content' => $lang['stralter'], |
|
172 | 'attr' => [ |
|
173 | 'href' => [ |
|
174 | 'url' => 'viewproperties.php', |
|
175 | 'urlvars' => [ |
|
176 | 'action' => 'confirm_alter', |
|
177 | 'view' => Decorator::field('relname'), |
|
178 | ], |
|
179 | ], |
|
180 | ], |
|
181 | ], |
|
182 | 'drop' => [ |
|
183 | 'multiaction' => 'confirm_drop', |
|
184 | 'content' => $lang['strdrop'], |
|
185 | 'attr' => [ |
|
186 | 'href' => [ |
|
187 | 'url' => 'views.php', |
|
188 | 'urlvars' => [ |
|
189 | 'action' => 'confirm_drop', |
|
190 | 'view' => Decorator::field('relname'), |
|
191 | ], |
|
192 | ], |
|
193 | ], |
|
194 | ], |
|
195 | ]; |
|
196 | ||
197 | echo $this->printTable($views, $columns, $actions, $this->table_place, $lang['strnoviews']); |
|
198 | ||
199 | $navlinks = [ |
|
200 | 'create' => [ |
|
201 | 'attr' => [ |
|
202 | 'href' => [ |
|
203 | 'url' => 'views.php', |
|
204 | 'urlvars' => [ |
|
205 | 'action' => 'create', |
|
206 | 'server' => $_REQUEST['server'], |
|
207 | 'database' => $_REQUEST['database'], |
|
208 | 'schema' => $_REQUEST['schema'], |
|
209 | ], |
|
210 | ], |
|
211 | ], |
|
212 | 'content' => $lang['strcreateview'], |
|
213 | ], |
|
214 | 'createwiz' => [ |
|
215 | 'attr' => [ |
|
216 | 'href' => [ |
|
217 | 'url' => 'views.php', |
|
218 | 'urlvars' => [ |
|
219 | 'action' => 'wiz_create', |
|
220 | 'server' => $_REQUEST['server'], |
|
221 | 'database' => $_REQUEST['database'], |
|
222 | 'schema' => $_REQUEST['schema'], |
|
223 | ], |
|
224 | ], |
|
225 | ], |
|
226 | 'content' => $lang['strcreateviewwiz'], |
|
227 | ], |
|
228 | ]; |
|
229 | $this->printNavLinks($navlinks, $this->table_place, get_defined_vars()); |
|
230 | } |
|
231 | ||
232 | /** |
|
233 | * Generate XML for the browser tree. |
|
234 | */ |
|
235 | public function doTree() |
|
236 | { |
|
237 | $conf = $this->conf; |
|
238 | $misc = $this->misc; |
|
239 | $lang = $this->lang; |
|
240 | $data = $misc->getDatabaseAccessor(); |
|
241 | ||
242 | $views = $data->getViews(); |
|
243 | ||
244 | $reqvars = $misc->getRequestVars('view'); |
|
245 | ||
246 | $attrs = [ |
|
247 | 'text' => Decorator::field('relname'), |
|
248 | 'icon' => 'View', |
|
249 | 'iconAction' => Decorator::url('display.php', $reqvars, ['view' => Decorator::field('relname')]), |
|
250 | 'toolTip' => Decorator::field('relcomment'), |
|
251 | 'action' => Decorator::redirecturl('redirect.php', $reqvars, ['view' => Decorator::field('relname')]), |
|
252 | 'branch' => Decorator::url('views.php', $reqvars, ['action' => 'subtree', 'view' => Decorator::field('relname')]), |
|
253 | ]; |
|
254 | ||
255 | return $this->printTree($views, $attrs, 'views'); |
|
256 | } |
|
257 | ||
258 | public function doSubTree() |
|
259 | { |
|
260 | $conf = $this->conf; |
|
261 | $misc = $this->misc; |
|
262 | $lang = $this->lang; |
|
263 | $data = $misc->getDatabaseAccessor(); |
|
264 | ||
265 | $tabs = $misc->getNavTabs('view'); |
|
266 | $items = $this->adjustTabsForTree($tabs); |
|
267 | $reqvars = $misc->getRequestVars('view'); |
|
268 | ||
269 | $attrs = [ |
|
270 | 'text' => Decorator::field('title'), |
|
271 | 'icon' => Decorator::field('icon'), |
|
272 | 'action' => Decorator::actionurl(Decorator::field('url'), $reqvars, Decorator::field('urlvars'), ['view' => $_REQUEST['view']]), |
|
273 | 'branch' => Decorator::ifempty( |
|
274 | Decorator::field('branch'), '', Decorator::url(Decorator::field('url'), Decorator::field('urlvars'), $reqvars, |
|
275 | [ |
|
276 | 'action' => 'tree', |
|
277 | 'view' => $_REQUEST['view'], |
|
278 | ] |
|
279 | ) |
|
280 | ), |
|
281 | ]; |
|
282 | ||
283 | return $this->printTree($items, $attrs, 'view'); |
|
284 | } |
|
285 | ||
286 | /** |
|
287 | * Ask for select parameters and perform select |
|
288 | */ |
|
289 | public function doSelectRows($confirm, $msg = '') |
|
290 | { |
|
291 | $conf = $this->conf; |
|
292 | $misc = $this->misc; |
|
293 | $lang = $this->lang; |
|
294 | $data = $misc->getDatabaseAccessor(); |
|
295 | ||
296 | if ($confirm) { |
|
297 | $this->printTrail('view'); |
|
298 | $this->printTabs('view', 'select'); |
|
299 | $this->printMsg($msg); |
|
300 | ||
301 | $attrs = $data->getTableAttributes($_REQUEST['view']); |
|
302 | ||
303 | echo '<form action="' . SUBFOLDER . '/src/views/' . $this->script . '" method="post" id="selectform">'; |
|
304 | echo "\n"; |
|
305 | ||
306 | if ($attrs->recordCount() > 0) { |
|
307 | // JavaScript for select all feature |
|
308 | echo "<script type=\"text/javascript\">\n"; |
|
309 | echo "//<![CDATA[\n"; |
|
310 | echo " function selectAll() {\n"; |
|
311 | echo " for (var i=0; i<document.getElementById('selectform').elements.length; i++) {\n"; |
|
312 | echo " var e = document.getElementById('selectform').elements[i];\n"; |
|
313 | echo " if (e.name.indexOf('show') == 0) { \n "; |
|
314 | echo " e.checked = document.getElementById('selectform').selectall.checked;\n"; |
|
315 | echo " }\n"; |
|
316 | echo " }\n"; |
|
317 | echo " }\n"; |
|
318 | echo "//]]>\n"; |
|
319 | echo "</script>\n"; |
|
320 | ||
321 | echo "<table>\n"; |
|
322 | ||
323 | // Output table header |
|
324 | echo "<tr><th class=\"data\">{$lang['strshow']}</th><th class=\"data\">{$lang['strcolumn']}</th>"; |
|
325 | echo "<th class=\"data\">{$lang['strtype']}</th><th class=\"data\">{$lang['stroperator']}</th>"; |
|
326 | echo "<th class=\"data\">{$lang['strvalue']}</th></tr>"; |
|
327 | ||
328 | $i = 0; |
|
329 | while (!$attrs->EOF) { |
|
330 | $attrs->fields['attnotnull'] = $data->phpBool($attrs->fields['attnotnull']); |
|
331 | // Set up default value if there isn't one already |
|
332 | if (!isset($_REQUEST['values'][$attrs->fields['attname']])) { |
|
333 | $_REQUEST['values'][$attrs->fields['attname']] = null; |
|
334 | } |
|
335 | ||
336 | if (!isset($_REQUEST['ops'][$attrs->fields['attname']])) { |
|
337 | $_REQUEST['ops'][$attrs->fields['attname']] = null; |
|
338 | } |
|
339 | ||
340 | // Continue drawing row |
|
341 | $id = (($i % 2) == 0 ? '1' : '2'); |
|
342 | echo "<tr class=\"data{$id}\">\n"; |
|
343 | echo '<td style="white-space:nowrap;">'; |
|
344 | echo '<input type="checkbox" name="show[', htmlspecialchars($attrs->fields['attname']), ']"', |
|
345 | isset($_REQUEST['show'][$attrs->fields['attname']]) ? ' checked="checked"' : '', ' /></td>'; |
|
346 | echo '<td style="white-space:nowrap;">', $misc->printVal($attrs->fields['attname']), '</td>'; |
|
347 | echo '<td style="white-space:nowrap;">', $misc->printVal($data->formatType($attrs->fields['type'], $attrs->fields['atttypmod'])), '</td>'; |
|
348 | echo '<td style="white-space:nowrap;">'; |
|
349 | echo "<select name=\"ops[{$attrs->fields['attname']}]\">\n"; |
|
350 | foreach (array_keys($data->selectOps) as $v) { |
|
351 | echo '<option value="', htmlspecialchars($v), '"', ($v == $_REQUEST['ops'][$attrs->fields['attname']]) ? ' selected="selected"' : '', |
|
352 | '>', htmlspecialchars($v), "</option>\n"; |
|
353 | } |
|
354 | echo "</select></td>\n"; |
|
355 | echo '<td style="white-space:nowrap;">', $data->printField("values[{$attrs->fields['attname']}]", |
|
356 | $_REQUEST['values'][$attrs->fields['attname']], $attrs->fields['type']), '</td>'; |
|
357 | echo "</tr>\n"; |
|
358 | $i++; |
|
359 | $attrs->moveNext(); |
|
360 | } |
|
361 | // Select all checkbox |
|
362 | echo "<tr><td colspan=\"5\"><input type=\"checkbox\" id=\"selectall\" name=\"selectall\" accesskey=\"a\" onclick=\"javascript:selectAll()\" /><label for=\"selectall\">{$lang['strselectallfields']}</label></td></tr>"; |
|
363 | echo "</table>\n"; |
|
364 | } else { |
|
365 | echo "<p>{$lang['strinvalidparam']}</p>\n"; |
|
366 | } |
|
367 | ||
368 | echo "<p><input type=\"hidden\" name=\"action\" value=\"selectrows\" />\n"; |
|
369 | echo '<input type="hidden" name="view" value="', htmlspecialchars($_REQUEST['view']), "\" />\n"; |
|
370 | echo "<input type=\"hidden\" name=\"subject\" value=\"view\" />\n"; |
|
371 | echo $misc->form; |
|
372 | echo "<input type=\"submit\" name=\"select\" accesskey=\"r\" value=\"{$lang['strselect']}\" />\n"; |
|
373 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; |
|
374 | echo "</form>\n"; |
|
375 | return; |
|
376 | } else { |
|
377 | if (!isset($_POST['show'])) { |
|
378 | $_POST['show'] = []; |
|
379 | } |
|
380 | ||
381 | if (!isset($_POST['values'])) { |
|
382 | $_POST['values'] = []; |
|
383 | } |
|
384 | ||
385 | if (!isset($_POST['nulls'])) { |
|
386 | $_POST['nulls'] = []; |
|
387 | } |
|
388 | ||
389 | // Verify that they haven't supplied a value for unary operators |
|
390 | foreach ($_POST['ops'] as $k => $v) { |
|
391 | if ($data->selectOps[$v] == 'p' && $_POST['values'][$k] != '') { |
|
392 | $this->doSelectRows(true, $lang['strselectunary']); |
|
393 | return; |
|
394 | } |
|
395 | } |
|
396 | ||
397 | if (sizeof($_POST['show']) == 0) { |
|
398 | return $this->doSelectRows(true, $lang['strselectneedscol']); |
|
399 | } else { |
|
400 | // Generate query SQL |
|
401 | $query = $data->getSelectSQL($_REQUEST['view'], array_keys($_POST['show']), $_POST['values'], $_POST['ops']); |
|
402 | ||
403 | $_REQUEST['query'] = $query; |
|
404 | $_REQUEST['return'] = 'schema'; |
|
405 | ||
406 | $this->setNoOutput(true); |
|
407 | ||
408 | $display_controller = new DisplayController($this->getContainer()); |
|
409 | ||
410 | return $display_controller->render(); |
|
411 | } |
|
412 | } |
|
413 | } |
|
414 | ||
415 | /** |
|
416 | * Show confirmation of drop and perform actual drop |
|
417 | */ |
|
418 | public function doDrop($confirm) |
|
419 | { |
|
420 | $conf = $this->conf; |
|
421 | $misc = $this->misc; |
|
422 | $lang = $this->lang; |
|
423 | $data = $misc->getDatabaseAccessor(); |
|
424 | ||
425 | if (empty($_REQUEST['view']) && empty($_REQUEST['ma'])) { |
|
426 | $this->doDefault($lang['strspecifyviewtodrop']); |
|
427 | exit(); |
|
428 | } |
|
429 | ||
430 | if ($confirm) { |
|
431 | $this->printTrail('view'); |
|
432 | $this->printTitle($lang['strdrop'], 'pg.view.drop'); |
|
433 | ||
434 | echo '<form action="' . SUBFOLDER . "/src/views/views.php\" method=\"post\">\n"; |
|
435 | ||
436 | //If multi drop |
|
437 | if (isset($_REQUEST['ma'])) { |
|
438 | foreach ($_REQUEST['ma'] as $v) { |
|
439 | $a = unserialize(htmlspecialchars_decode($v, ENT_QUOTES)); |
|
440 | echo '<p>', sprintf($lang['strconfdropview'], $misc->printVal($a['view'])), "</p>\n"; |
|
441 | echo '<input type="hidden" name="view[]" value="', htmlspecialchars($a['view']), "\" />\n"; |
|
442 | } |
|
443 | } else { |
|
444 | echo '<p>', sprintf($lang['strconfdropview'], $misc->printVal($_REQUEST['view'])), "</p>\n"; |
|
445 | echo '<input type="hidden" name="view" value="', htmlspecialchars($_REQUEST['view']), "\" />\n"; |
|
446 | } |
|
447 | ||
448 | echo "<input type=\"hidden\" name=\"action\" value=\"drop\" />\n"; |
|
449 | ||
450 | echo $misc->form; |
|
451 | echo "<p><input type=\"checkbox\" id=\"cascade\" name=\"cascade\" /> <label for=\"cascade\">{$lang['strcascade']}</label></p>\n"; |
|
452 | echo "<input type=\"submit\" name=\"drop\" value=\"{$lang['strdrop']}\" />\n"; |
|
453 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" />\n"; |
|
454 | echo "</form>\n"; |
|
455 | } else { |
|
456 | if (is_array($_POST['view'])) { |
|
457 | $msg = ''; |
|
458 | $status = $data->beginTransaction(); |
|
459 | if ($status == 0) { |
|
460 | foreach ($_POST['view'] as $s) { |
|
461 | $status = $data->dropView($s, isset($_POST['cascade'])); |
|
462 | if ($status == 0) { |
|
463 | $msg .= sprintf('%s: %s<br />', htmlentities($s, ENT_QUOTES, 'UTF-8'), $lang['strviewdropped']); |
|
464 | } else { |
|
465 | $data->endTransaction(); |
|
466 | $this->doDefault(sprintf('%s%s: %s<br />', $msg, htmlentities($s, ENT_QUOTES, 'UTF-8'), $lang['strviewdroppedbad'])); |
|
467 | return; |
|
468 | } |
|
469 | } |
|
470 | } |
|
471 | if ($data->endTransaction() == 0) { |
|
472 | // Everything went fine, back to the Default page.... |
|
473 | $this->misc->setReloadBrowser(true); |
|
474 | $this->doDefault($msg); |
|
475 | } else { |
|
476 | $this->doDefault($lang['strviewdroppedbad']); |
|
477 | } |
|
478 | } else { |
|
479 | $status = $data->dropView($_POST['view'], isset($_POST['cascade'])); |
|
480 | if ($status == 0) { |
|
481 | $this->misc->setReloadBrowser(true); |
|
482 | $this->doDefault($lang['strviewdropped']); |
|
483 | } else { |
|
484 | $this->doDefault($lang['strviewdroppedbad']); |
|
485 | } |
|
486 | } |
|
487 | } |
|
488 | } |
|
489 | ||
490 | /** |
|
491 | * Sets up choices for table linkage, and which fields to select for the view we're creating |
|
492 | */ |
|
493 | public function doSetParamsCreate($msg = '') |
|
494 | { |
|
495 | $conf = $this->conf; |
|
496 | $misc = $this->misc; |
|
497 | $lang = $this->lang; |
|
498 | $data = $misc->getDatabaseAccessor(); |
|
499 | ||
500 | // Check that they've chosen tables for the view definition |
|
501 | if (!isset($_POST['formTables'])) { |
|
502 | $this->doWizardCreate($lang['strviewneedsdef']); |
|
503 | } else { |
|
504 | // Initialise variables |
|
505 | if (!isset($_REQUEST['formView'])) { |
|
506 | $_REQUEST['formView'] = ''; |
|
507 | } |
|
508 | ||
509 | if (!isset($_REQUEST['formComment'])) { |
|
510 | $_REQUEST['formComment'] = ''; |
|
511 | } |
|
512 | ||
513 | $this->printTrail('schema'); |
|
514 | $this->printTitle($lang['strcreateviewwiz'], 'pg.view.create'); |
|
515 | $this->printMsg($msg); |
|
516 | ||
517 | $tblCount = sizeof($_POST['formTables']); |
|
518 | //unserialize our schema/table information and store in arrSelTables |
|
519 | for ($i = 0; $i < $tblCount; $i++) { |
|
520 | $arrSelTables[] = unserialize($_POST['formTables'][$i]); |
|
521 | } |
|
522 | ||
523 | $linkCount = $tblCount; |
|
524 | ||
525 | //get linking keys |
|
526 | $rsLinkKeys = $data->getLinkingKeys($arrSelTables); |
|
527 | $linkCount = $rsLinkKeys->recordCount() > $tblCount ? $rsLinkKeys->recordCount() : $tblCount; |
|
528 | ||
529 | $arrFields = []; //array that will hold all our table/field names |
|
530 | ||
531 | //if we have schemas we need to specify the correct schema for each table we're retrieiving |
|
532 | //with getTableAttributes |
|
533 | $curSchema = $data->_schema; |
|
534 | for ($i = 0; $i < $tblCount; $i++) { |
|
535 | if ($data->_schema != $arrSelTables[$i]['schemaname']) { |
|
536 | $data->setSchema($arrSelTables[$i]['schemaname']); |
|
537 | } |
|
538 | ||
539 | $attrs = $data->getTableAttributes($arrSelTables[$i]['tablename']); |
|
540 | while (!$attrs->EOF) { |
|
541 | $arrFields["{$arrSelTables[$i]['schemaname']}.{$arrSelTables[$i]['tablename']}.{$attrs->fields['attname']}"] = serialize([ |
|
542 | 'schemaname' => $arrSelTables[$i]['schemaname'], |
|
543 | 'tablename' => $arrSelTables[$i]['tablename'], |
|
544 | 'fieldname' => $attrs->fields['attname']] |
|
545 | ); |
|
546 | $attrs->moveNext(); |
|
547 | } |
|
548 | ||
549 | $data->setSchema($curSchema); |
|
550 | } |
|
551 | asort($arrFields); |
|
552 | ||
553 | echo '<form action="' . SUBFOLDER . "/src/views/views.php\" method=\"post\">\n"; |
|
554 | echo "<table>\n"; |
|
555 | echo "<tr><th class=\"data\">{$lang['strviewname']}</th></tr>"; |
|
556 | echo "<tr>\n<td class=\"data1\">\n"; |
|
557 | // View name |
|
558 | echo '<input name="formView" value="', htmlspecialchars($_REQUEST['formView']), "\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" />\n"; |
|
559 | echo "</td>\n</tr>\n"; |
|
560 | echo "<tr><th class=\"data\">{$lang['strcomment']}</th></tr>"; |
|
561 | echo "<tr>\n<td class=\"data1\">\n"; |
|
562 | // View comments |
|
563 | echo '<textarea name="formComment" rows="3" cols="32">', |
|
564 | htmlspecialchars($_REQUEST['formComment']), "</textarea>\n"; |
|
565 | echo "</td>\n</tr>\n"; |
|
566 | echo "</table>\n"; |
|
567 | ||
568 | // Output selector for fields to be retrieved from view |
|
569 | echo "<table>\n"; |
|
570 | echo "<tr><th class=\"data\">{$lang['strcolumns']}</th></tr>"; |
|
571 | echo "<tr>\n<td class=\"data1\">\n"; |
|
572 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, 'formFields[]', false, '', true); |
|
573 | echo "</td>\n</tr>"; |
|
574 | echo "<tr><td><input type=\"radio\" name=\"dblFldMeth\" id=\"dblFldMeth1\" value=\"rename\" /><label for=\"dblFldMeth1\">{$lang['strrenamedupfields']}</label>"; |
|
575 | echo "<br /><input type=\"radio\" name=\"dblFldMeth\" id=\"dblFldMeth2\" value=\"drop\" /><label for=\"dblFldMeth2\">{$lang['strdropdupfields']}</label>"; |
|
576 | echo "<br /><input type=\"radio\" name=\"dblFldMeth\" id=\"dblFldMeth3\" value=\"\" checked=\"checked\" /><label for=\"dblFldMeth3\">{$lang['strerrordupfields']}</label></td></tr></table><br />"; |
|
577 | ||
578 | // Output the Linking keys combo boxes |
|
579 | echo "<table>\n"; |
|
580 | echo "<tr><th class=\"data\">{$lang['strviewlink']}</th></tr>"; |
|
581 | $rowClass = 'data1'; |
|
582 | for ($i = 0; $i < $linkCount; $i++) { |
|
583 | // Initialise variables |
|
584 | if (!isset($formLink[$i]['operator'])) { |
|
585 | $formLink[$i]['operator'] = 'INNER JOIN'; |
|
586 | } |
|
587 | ||
588 | echo "<tr>\n<td class=\"$rowClass\">\n"; |
|
589 | ||
590 | if (!$rsLinkKeys->EOF) { |
|
591 | $curLeftLink = htmlspecialchars(serialize(['schemaname' => $rsLinkKeys->fields['p_schema'], 'tablename' => $rsLinkKeys->fields['p_table'], 'fieldname' => $rsLinkKeys->fields['p_field']])); |
|
592 | $curRightLink = htmlspecialchars(serialize(['schemaname' => $rsLinkKeys->fields['f_schema'], 'tablename' => $rsLinkKeys->fields['f_table'], 'fieldname' => $rsLinkKeys->fields['f_field']])); |
|
593 | $rsLinkKeys->moveNext(); |
|
594 | } else { |
|
595 | $curLeftLink = ''; |
|
596 | $curRightLink = ''; |
|
597 | } |
|
598 | ||
599 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, "formLink[$i][leftlink]", true, $curLeftLink, false); |
|
600 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($data->joinOps, "formLink[$i][operator]", true, $formLink[$i]['operator']); |
|
601 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, "formLink[$i][rightlink]", true, $curRightLink, false); |
|
602 | echo "</td>\n</tr>\n"; |
|
603 | $rowClass = $rowClass == 'data1' ? 'data2' : 'data1'; |
|
604 | } |
|
605 | echo "</table>\n<br />\n"; |
|
606 | ||
607 | // Build list of available operators (infix only) |
|
608 | $arrOperators = []; |
|
609 | foreach ($data->selectOps as $k => $v) { |
|
610 | if ($v == 'i') { |
|
611 | $arrOperators[$k] = $k; |
|
612 | } |
|
613 | } |
|
614 | ||
615 | // Output additional conditions, note that this portion of the wizard treats the right hand side as literal values |
|
616 | //(not as database objects) so field names will be treated as strings, use the above linking keys section to perform joins |
|
617 | echo "<table>\n"; |
|
618 | echo "<tr><th class=\"data\">{$lang['strviewconditions']}</th></tr>"; |
|
619 | $rowClass = 'data1'; |
|
620 | for ($i = 0; $i < $linkCount; $i++) { |
|
621 | echo "<tr>\n<td class=\"$rowClass\">\n"; |
|
622 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrFields, "formCondition[$i][field]"); |
|
623 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrOperators, "formCondition[$i][operator]", false, false); |
|
624 | echo "<input type=\"text\" name=\"formCondition[$i][txt]\" />\n"; |
|
625 | echo "</td>\n</tr>\n"; |
|
626 | $rowClass = $rowClass == 'data1' ? 'data2' : 'data1'; |
|
627 | } |
|
628 | echo "</table>\n"; |
|
629 | echo "<p><input type=\"hidden\" name=\"action\" value=\"save_create_wiz\" />\n"; |
|
630 | ||
631 | foreach ($arrSelTables as $curTable) { |
|
632 | echo '<input type="hidden" name="formTables[]" value="' . htmlspecialchars(serialize($curTable)) . "\" />\n"; |
|
633 | } |
|
634 | ||
635 | echo $misc->form; |
|
636 | echo "<input type=\"submit\" value=\"{$lang['strcreate']}\" />\n"; |
|
637 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; |
|
638 | echo "</form>\n"; |
|
639 | } |
|
640 | } |
|
641 | ||
642 | /** |
|
643 | * Display a wizard where they can enter a new view |
|
644 | */ |
|
645 | public function doWizardCreate($msg = '') |
|
646 | { |
|
647 | $conf = $this->conf; |
|
648 | $misc = $this->misc; |
|
649 | $lang = $this->lang; |
|
650 | $data = $misc->getDatabaseAccessor(); |
|
651 | ||
652 | $tables = $data->getTables(true); |
|
653 | ||
654 | $this->printTrail('schema'); |
|
655 | $this->printTitle($lang['strcreateviewwiz'], 'pg.view.create'); |
|
656 | $this->printMsg($msg); |
|
657 | ||
658 | echo '<form action="' . SUBFOLDER . "/src/views/views.php\" method=\"post\">\n"; |
|
659 | echo "<table>\n"; |
|
660 | echo "<tr><th class=\"data\">{$lang['strtables']}</th></tr>"; |
|
661 | echo "<tr>\n<td class=\"data1\">\n"; |
|
662 | ||
663 | $arrTables = []; |
|
664 | while (!$tables->EOF) { |
|
665 | $arrTmp = []; |
|
666 | $arrTmp['schemaname'] = $tables->fields['nspname']; |
|
667 | $arrTmp['tablename'] = $tables->fields['relname']; |
|
668 | $arrTables[$tables->fields['nspname'] . '.' . $tables->fields['relname']] = serialize($arrTmp); |
|
669 | $tables->moveNext(); |
|
670 | } |
|
671 | echo \PHPPgAdmin\XHtml\HTMLController::printCombo($arrTables, 'formTables[]', false, '', true); |
|
672 | ||
673 | echo "</td>\n</tr>\n"; |
|
674 | echo "</table>\n"; |
|
675 | echo "<p><input type=\"hidden\" name=\"action\" value=\"set_params_create\" />\n"; |
|
676 | echo $misc->form; |
|
677 | echo "<input type=\"submit\" value=\"{$lang['strnext']}\" />\n"; |
|
678 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; |
|
679 | echo "</form>\n"; |
|
680 | } |
|
681 | ||
682 | /** |
|
683 | * Displays a screen where they can enter a new view |
|
684 | */ |
|
685 | public function doCreate($msg = '') |
|
686 | { |
|
687 | $conf = $this->conf; |
|
688 | $misc = $this->misc; |
|
689 | $lang = $this->lang; |
|
690 | $data = $misc->getDatabaseAccessor(); |
|
691 | ||
692 | if (!isset($_REQUEST['formView'])) { |
|
693 | $_REQUEST['formView'] = ''; |
|
694 | } |
|
695 | ||
696 | if (!isset($_REQUEST['formDefinition'])) { |
|
697 | if (isset($_SESSION['sqlquery'])) { |
|
698 | $_REQUEST['formDefinition'] = $_SESSION['sqlquery']; |
|
699 | } else { |
|
700 | $_REQUEST['formDefinition'] = 'SELECT '; |
|
701 | } |
|
702 | } |
|
703 | if (!isset($_REQUEST['formComment'])) { |
|
704 | $_REQUEST['formComment'] = ''; |
|
705 | } |
|
706 | ||
707 | $this->printTrail('schema'); |
|
708 | $this->printTitle($lang['strcreateview'], 'pg.view.create'); |
|
709 | $this->printMsg($msg); |
|
710 | ||
711 | echo '<form action="' . SUBFOLDER . "/src/views/views.php\" method=\"post\">\n"; |
|
712 | echo "<table style=\"width: 100%\">\n"; |
|
713 | echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strname']}</th>\n"; |
|
714 | echo "\t<td class=\"data1\"><input name=\"formView\" size=\"32\" maxlength=\"{$data->_maxNameLen}\" value=\"", |
|
715 | htmlspecialchars($_REQUEST['formView']), "\" /></td>\n\t</tr>\n"; |
|
716 | echo "\t<tr>\n\t\t<th class=\"data left required\">{$lang['strdefinition']}</th>\n"; |
|
717 | echo "\t<td class=\"data1\"><textarea style=\"width:100%;\" rows=\"10\" cols=\"50\" name=\"formDefinition\">", |
|
718 | htmlspecialchars($_REQUEST['formDefinition']), "</textarea></td>\n\t</tr>\n"; |
|
719 | echo "\t<tr>\n\t\t<th class=\"data left\">{$lang['strcomment']}</th>\n"; |
|
720 | echo "\t\t<td class=\"data1\"><textarea name=\"formComment\" rows=\"3\" cols=\"32\">", |
|
721 | htmlspecialchars($_REQUEST['formComment']), "</textarea></td>\n\t</tr>\n"; |
|
722 | echo "</table>\n"; |
|
723 | echo "<p><input type=\"hidden\" name=\"action\" value=\"save_create\" />\n"; |
|
724 | echo $misc->form; |
|
725 | echo "<input type=\"submit\" value=\"{$lang['strcreate']}\" />\n"; |
|
726 | echo "<input type=\"submit\" name=\"cancel\" value=\"{$lang['strcancel']}\" /></p>\n"; |
|
727 | echo "</form>\n"; |
|
728 | } |
|
729 | ||
730 | /** |
|
731 | * Actually creates the new view in the database |
|
732 | */ |
|
733 | public function doSaveCreate() |
|
734 | { |
|
735 | $conf = $this->conf; |
|
736 | $misc = $this->misc; |
|
737 | $lang = $this->lang; |
|
738 | $data = $misc->getDatabaseAccessor(); |
|
739 | ||
740 | // Check that they've given a name and a definition |
|
741 | if ($_POST['formView'] == '') { |
|
742 | $this->doCreate($lang['strviewneedsname']); |
|
743 | } elseif ($_POST['formDefinition'] == '') { |
|
744 | $this->doCreate($lang['strviewneedsdef']); |
|
745 | } else { |
|
746 | $status = $data->createView($_POST['formView'], $_POST['formDefinition'], false, $_POST['formComment']); |
|
747 | if ($status == 0) { |
|
748 | $this->misc->setReloadBrowser(true); |
|
749 | $this->doDefault($lang['strviewcreated']); |
|
750 | } else { |
|
751 | $this->doCreate($lang['strviewcreatedbad']); |
|
752 | } |
|
753 | } |
|
754 | } |
|
755 | ||
756 | /** |
|
757 | * Actually creates the new wizard view in the database |
|
758 | */ |
|
759 | public function doSaveCreateWiz() |
|
760 | { |
|
761 | $conf = $this->conf; |
|
762 | $misc = $this->misc; |
|
763 | $lang = $this->lang; |
|
764 | $data = $misc->getDatabaseAccessor(); |
|
765 | ||
766 | // Check that they've given a name and fields they want to select |
|
767 | ||
768 | if (!strlen($_POST['formView'])) { |
|
769 | $this->doSetParamsCreate($lang['strviewneedsname']); |
|
770 | } elseif (!isset($_POST['formFields']) || !count($_POST['formFields'])) { |
|
771 | $this->doSetParamsCreate($lang['strviewneedsfields']); |
|
772 | } else { |
|
773 | $selFields = ''; |
|
774 | ||
775 | if (!empty($_POST['dblFldMeth'])) { |
|
776 | $tmpHsh = []; |
|
777 | } |
|
778 | ||
779 | foreach ($_POST['formFields'] as $curField) { |
|
780 | $arrTmp = unserialize($curField); |
|
781 | $data->fieldArrayClean($arrTmp); |
|
782 | if (!empty($_POST['dblFldMeth'])) { |
|
783 | // doublon control |
|
784 | if (empty($tmpHsh[$arrTmp['fieldname']])) { |
|
785 | // field does not exist |
|
786 | $selFields .= "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\", "; |
|
787 | $tmpHsh[$arrTmp['fieldname']] = 1; |
|
788 | } elseif ($_POST['dblFldMeth'] == 'rename') { |
|
789 | // field exist and must be renamed |
|
790 | $tmpHsh[$arrTmp['fieldname']]++; |
|
791 | $selFields .= "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" AS \"{$arrTmp['schemaname']}_{$arrTmp['tablename']}_{$arrTmp['fieldname']}{$tmpHsh[$arrTmp['fieldname']]}\", "; |
|
792 | } |
|
793 | /* field already exist, just ignore this one */ |
|
794 | } else { |
|
795 | // no doublon control |
|
796 | $selFields .= "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\", "; |
|
797 | } |
|
798 | } |
|
799 | ||
800 | $selFields = substr($selFields, 0, -2); |
|
801 | unset($arrTmp, $tmpHsh); |
|
802 | $linkFields = ''; |
|
803 | ||
804 | // If we have links, out put the JOIN ... ON statements |
|
805 | if (is_array($_POST['formLink'])) { |
|
806 | // Filter out invalid/blank entries for our links |
|
807 | $arrLinks = []; |
|
808 | foreach ($_POST['formLink'] as $curLink) { |
|
809 | if (strlen($curLink['leftlink']) && strlen($curLink['rightlink']) && strlen($curLink['operator'])) { |
|
810 | $arrLinks[] = $curLink; |
|
811 | } |
|
812 | } |
|
813 | // We must perform some magic to make sure that we have a valid join order |
|
814 | $count = sizeof($arrLinks); |
|
815 | $arrJoined = []; |
|
816 | $arrUsedTbls = []; |
|
817 | ||
818 | // If we have at least one join condition, output it |
|
819 | if ($count > 0) { |
|
820 | $j = 0; |
|
821 | while ($j < $count) { |
|
822 | foreach ($arrLinks as $curLink) { |
|
823 | $arrLeftLink = unserialize($curLink['leftlink']); |
|
824 | $arrRightLink = unserialize($curLink['rightlink']); |
|
825 | $data->fieldArrayClean($arrLeftLink); |
|
826 | $data->fieldArrayClean($arrRightLink); |
|
827 | ||
828 | $tbl1 = "\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\""; |
|
829 | $tbl2 = "\"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\""; |
|
830 | ||
831 | if ((!in_array($curLink, $arrJoined) && in_array($tbl1, $arrUsedTbls)) || !count($arrJoined)) { |
|
832 | ||
833 | // Make sure for multi-column foreign keys that we use a table alias tables joined to more than once |
|
834 | // This can (and should be) more optimized for multi-column foreign keys |
|
835 | $adj_tbl2 = in_array($tbl2, $arrUsedTbls) ? "$tbl2 AS alias_ppa_" . mktime() : $tbl2; |
|
836 | ||
837 | $linkFields .= strlen($linkFields) ? "{$curLink['operator']} $adj_tbl2 ON (\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\".\"{$arrLeftLink['fieldname']}\" = \"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\".\"{$arrRightLink['fieldname']}\") " |
|
838 | : "$tbl1 {$curLink['operator']} $adj_tbl2 ON (\"{$arrLeftLink['schemaname']}\".\"{$arrLeftLink['tablename']}\".\"{$arrLeftLink['fieldname']}\" = \"{$arrRightLink['schemaname']}\".\"{$arrRightLink['tablename']}\".\"{$arrRightLink['fieldname']}\") "; |
|
839 | ||
840 | $arrJoined[] = $curLink; |
|
841 | if (!in_array($tbl1, $arrUsedTbls)) { |
|
842 | $arrUsedTbls[] = $tbl1; |
|
843 | } |
|
844 | ||
845 | if (!in_array($tbl2, $arrUsedTbls)) { |
|
846 | $arrUsedTbls[] = $tbl2; |
|
847 | } |
|
848 | } |
|
849 | } |
|
850 | $j++; |
|
851 | } |
|
852 | } |
|
853 | } |
|
854 | ||
855 | //if linkfields has no length then either _POST['formLink'] was not set, or there were no join conditions |
|
856 | //just select from all seleted tables - a cartesian join do a |
|
857 | if (!strlen($linkFields)) { |
|
858 | foreach ($_POST['formTables'] as $curTable) { |
|
859 | $arrTmp = unserialize($curTable); |
|
860 | $data->fieldArrayClean($arrTmp); |
|
861 | $linkFields .= strlen($linkFields) ? ", \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\"" : "\"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\""; |
|
862 | } |
|
863 | } |
|
864 | ||
865 | $addConditions = ''; |
|
866 | if (is_array($_POST['formCondition'])) { |
|
867 | foreach ($_POST['formCondition'] as $curCondition) { |
|
868 | if (strlen($curCondition['field']) && strlen($curCondition['txt'])) { |
|
869 | $arrTmp = unserialize($curCondition['field']); |
|
870 | $data->fieldArrayClean($arrTmp); |
|
871 | $addConditions .= strlen($addConditions) ? " AND \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" {$curCondition['operator']} '{$curCondition['txt']}' " |
|
872 | : " \"{$arrTmp['schemaname']}\".\"{$arrTmp['tablename']}\".\"{$arrTmp['fieldname']}\" {$curCondition['operator']} '{$curCondition['txt']}' "; |
|
873 | } |
|
874 | } |
|
875 | } |
|
876 | ||
877 | $viewQuery = "SELECT $selFields FROM $linkFields "; |
|
878 | ||
879 | //add where from additional conditions |
|
880 | if (strlen($addConditions)) { |
|
881 | $viewQuery .= ' WHERE ' . $addConditions; |
|
882 | } |
|
883 | ||
884 | $status = $data->createView($_POST['formView'], $viewQuery, false, $_POST['formComment']); |
|
885 | if ($status == 0) { |
|
886 | $this->misc->setReloadBrowser(true); |
|
887 | $this->doDefault($lang['strviewcreated']); |
|
888 | } else { |
|
889 | $this->doSetParamsCreate($lang['strviewcreatedbad']); |
|
890 | } |
|
891 | } |
|
892 | } |
|
893 | } |
|
894 |