dbXapp 2.0
RAD, CMS, Module und Runtime-IDE fuer dbXapp
Loading...
Searching...
No Matches
dbxContent_treeview.class.php
Go to the documentation of this file.
1<?php
2namespace dbx\dbxContent;
3
4require_once __DIR__ . '/dbxContent_bootstrap.php';
5
7
8 private function needsCmsRuntime() {
10 }
11
12 private function render_frontend_view($cid, $pageContent) {
13 $tpl = dbx()->get_system_obj('dbxTPL');
14 $i = dbx()->next_id();
15 $title = $this->page_title($cid);
16
17 return $tpl->get_tpl('dbxContent|content-page-frontend', array(
18 'frame_id' => 'dbx_content_view_' . $i,
19 'cid' => (string)(int)$cid,
20 'frontend_head' => $tpl->get_tpl('dbxContent|content-frontend-head', array(
21 'bar_title' => $title,
22 'bar_title_pre' => $this->adminEditorBarHtml($cid, true),
23 'bar_title_heading_attrs' => ' data-cms-page-title',
24 )),
25 'page_content' => $pageContent,
26 ));
27 }
28
29 private function treeToggleBarHtml() {
31 return '';
32 }
33
34 return dbx()->get_system_obj('dbxTPL')->get_tpl('dbxContent|content-view-bar-tree-toggle');
35 }
36
37 private function adminEditorBarHtml($cid = 0, $useWindow = false) {
38 if (!dbx()->can('admin')) {
39 return '';
40 }
41
42 $tpl = dbx()->get_system_obj('dbxTPL');
43 $cid = (int)$cid;
44 if ($useWindow && $cid > 0) {
45 $url = $this->appUrl() . '?dbx_modul=dbxContent_admin&dbx_run1=cms&cid=' . $cid;
46 return $tpl->get_tpl('dbxContent|content-view-bar-admin-win', array(
47 'admin_url' => dbx()->esc($url),
48 ));
49 }
50
51 return $tpl->get_tpl('dbxContent|content-view-bar-admin');
52 }
53
54 private function appUrl() {
55 $script = str_replace('\\', '/', (string)($_SERVER['SCRIPT_NAME'] ?? ''));
56 if ($script === '') return '';
57 $dir = str_replace('\\', '/', dirname($script));
58 if ($dir === '.' || $dir === '/' || $dir === '\\') return '/';
59 return rtrim($dir, '/') . '/';
60 }
61
62 private function moduleFrameReplaces($barTitle, $i, $panelAttrs, $barAdmin = '', $barSubtitle = '', $barTreeToggle = '') {
63 $tpl = dbx()->get_system_obj('dbxTPL');
64
65 return array(
66 'frame_id' => 'dbx_content_tree_' . $i,
67 'frame_panel_class' => 'dbx-cms dbx-cms-view dbx-content-tree-view dbxReport',
68 'frame_body_class' => 'dbx-content-tree-body',
69 'frame_panel_attrs' => $panelAttrs,
70 'frame_subbar' => '',
71 'frame_form_open' => '',
72 'frame_form_close' => '',
73 'frame_body_head' => '',
74 'frame_body_tail' => '',
75 'bar_class' => 'dbx-module-bar dbx-cms-head',
76 'bar_title_class' => 'dbx-module-bar-titleblock',
77 'bar_actions_class' => 'dbx-module-bar-actions flex-nowrap',
78 'bar_title' => $barTitle,
79 'bar_icon' => 'bi-file-earmark-text',
80 'bar_subtitle' => $barSubtitle,
81 'bar_title_pre' => (string)$barAdmin . (string)$barTreeToggle,
82 'bar_title_heading_attrs' => ' data-cms-page-title',
83 'bar_middle' => '',
84 'bar_extra' => '',
85 'bar_actions' => $tpl->get_tpl('dbxContent|content-view-bar-actions'),
86 );
87 }
88
89 private function page_title($cid) {
90 $cid = (int)$cid;
91 if ($cid <= 0) {
92 return 'Keine Seite ausgewaehlt';
93 }
94
95 $db = dbx()->get_system_obj('dbxDB');
96 $row = $db->select1(dbxContentLng::ddContent(), $cid, 'title', 0);
97 if (!is_array($row)) {
98 return 'Seite #' . $cid;
99 }
100
101 $title = trim((string)($row['title'] ?? ''));
102 return $title !== '' ? $title : ('Seite #' . $cid);
103 }
104
105 private function base_url($action, $params = array()) {
106 $url = '?dbx_modul=dbxContent&dbx_run1=' . rawurlencode((string)$action);
107 foreach ($params as $key => $value) {
108 $url .= '&' . rawurlencode((string)$key) . '=' . rawurlencode((string)$value);
109 }
110 return $url;
111 }
112
113 private function root_id() {
114 return dbx()->get_modul_var('root', 0, 'int');
115 }
116
117 private function user_has_access($groups) {
118 $groups = trim((string)$groups);
119 if ($groups === '') $groups = '*';
120 return dbx()->can($groups);
121 }
122
123 private function dd_server($dd, $fallback) {
124 $db = dbx()->get_system_obj('dbxDB');
125 if (method_exists($db, 'load_dd')) {
126 $sys = $db->load_dd($dd);
127 $mod = $sys['dd_modul'] ?? 'dbx';
128 $name = $sys['dd_name'] ?? '';
129 if ($name && isset($_SESSION['dbx']['cache']['dd'][$mod][$name]['table']['server'])) {
130 return $_SESSION['dbx']['cache']['dd'][$mod][$name]['table']['server'];
131 }
132 }
133 return $fallback;
134 }
135
136 private function ensure_column($db, $server, $table, $name, $type) {
137 $server = (string)$server;
138 $table = preg_replace('/[^A-Za-z0-9_]+/', '', (string)$table);
139 $name = preg_replace('/[^A-Za-z0-9_]+/', '', (string)$name);
140 if ($server === '' || $table === '' || $name === '') return;
141
142 $cols = $db->select_query($server, 'PRAGMA table_info(' . $table . ')');
143 if (is_array($cols)) {
144 foreach ($cols as $col) {
145 if (isset($col['name']) && strtolower((string)$col['name']) === strtolower($name)) return;
146 }
147 }
148
149 $db->exec($server, 'ALTER TABLE ' . $table . ' ADD COLUMN ' . $name . ' ' . $type);
150 }
151
152 private function ensure_tree_schema($db) {
153 static $done = false;
154 if ($done) return;
155 $done = true;
156
157 $folder_server = $this->dd_server(dbxContentLng::ddFolder(), 'dbx|dbxContent.db3');
158 $folder_table = $db->get_dd_table(dbxContentLng::ddFolder());
159 $this->ensure_column($db, $folder_server, $folder_table, 'sorter', "TEXT DEFAULT ''");
160 }
161
162 private function resolve_folder_rights($db, $folder_id, array $visited = array()) {
163 $folder_id = (int)$folder_id;
164 if ($folder_id <= 0) return '*';
165 if (isset($visited[$folder_id])) return '*';
166 $visited[$folder_id] = 1;
167
168 $row = $db->select1(dbxContentLng::ddFolder(), $folder_id, '*', 0);
169 if (!is_array($row)) return '*';
170
171 $raw = trim((string)($row['group_read'] ?? ''));
172 if ($raw === '') return '*';
173
174 $parent_id = (int)($row['parent_id'] ?? 0);
175 $parts = preg_split('/\s*,\s*/', $raw, -1, PREG_SPLIT_NO_EMPTY);
176 $out = array();
177 $uses_parent = false;
178
179 foreach ($parts as $part) {
180 $part = trim((string)$part);
181 if ($part === '') continue;
182 if (strtolower($part) === 'parent') {
183 $uses_parent = true;
184 continue;
185 }
186 $out[$part] = 1;
187 }
188
189 if ($uses_parent) {
190 foreach (preg_split('/\s*,\s*/', $this->resolve_folder_rights($db, $parent_id, $visited), -1, PREG_SPLIT_NO_EMPTY) as $part) {
191 $part = trim((string)$part);
192 if ($part !== '' && strtolower($part) !== 'parent') $out[$part] = 1;
193 }
194 }
195
196 return count($out) ? implode(',', array_keys($out)) : '*';
197 }
198
199 private function resolve_page_rights($db, array $page) {
200 return $this->resolve_folder_rights($db, (int)($page['folder'] ?? 0));
201 }
202
203 private function row_html(array $node) {
204 $tpl = dbx()->get_system_obj('dbxTPL');
205 $type = ($node['_type'] ?? '') === 'folder' ? 'folder' : 'page';
206 $title = dbx()->esc((string)($node['_title'] ?? ''));
207 $data = array(
208 '_type' => $type,
209 '_id' => (string)(int)($node['_id'] ?? 0),
210 '_parent' => (string)(int)($node['_parent'] ?? 0),
211 'draggable_attr' => '',
212 'icon' => $type === 'folder' ? '<i class="bi bi-folder2-open"></i>' : '<i class="bi bi-file-earmark-text"></i>',
213 'folder_id_label' => '',
214 'title_label' => $title,
215 'rights_label' => '',
216 );
217 return $tpl->get_tpl('dbxContent|content-tree-row', $data);
218 }
219
220 private function decorate_nodes(array $nodes, array &$flat) {
221 $db = dbx()->get_system_obj('dbxDB');
222 $out = array();
223 foreach ($nodes as $node) {
224 if (!is_array($node)) continue;
225 $type = ($node['_type'] ?? '') === 'folder' ? 'folder' : 'page';
226 $id = (int)($node['_id'] ?? 0);
227 if ($id <= 0) continue;
228
229 if ($type === 'folder') {
230 if (!$this->user_has_access($this->resolve_folder_rights($db, $id))) continue;
231 $node['_children'] = $this->decorate_nodes(is_array($node['_children'] ?? null) ? $node['_children'] : array(), $flat);
232 if (!count($node['_children'])) continue;
233 } else {
234 $page = $db->select1(dbxContentLng::ddContent(), $id, '*', 0);
235 if (!is_array($page) || (int)($page['activ'] ?? 0) !== 1) continue;
236 if (!$this->user_has_access($this->resolve_page_rights($db, $page))) continue;
237 $node['_parent'] = (int)($page['folder'] ?? 0);
238 }
239
240 $node['_row_html'] = $this->row_html($node);
241 $flat[] = $node;
242 $out[] = $node;
243 }
244 return $out;
245 }
246
247 private function tree() {
248 $db = dbx()->get_system_obj('dbxDB');
249 $this->ensure_tree_schema($db);
250 $root = $this->root_id();
251 if ($root > 0 && !$this->user_has_access($this->resolve_folder_rights($db, $root))) {
252 return array(
253 'nodes' => array(),
254 'flat' => array(),
255 'count_pages' => 0,
256 'count_folders' => 0,
257 );
258 }
259
260 $tree = $db->select_tree(dbxContentLng::ddFolder(), dbxContentLng::ddContent(), array(
261 'root' => $root,
262 'verify_access' => 0,
263 'item_where' => 'activ = 1',
264 ));
265 $flat = array();
266 $nodes = $this->decorate_nodes(is_array($tree['nodes'] ?? null) ? $tree['nodes'] : array(), $flat);
267
268 return array(
269 'nodes' => $nodes,
270 'flat' => $flat,
271 'count_pages' => count(array_filter($flat, function($node) { return ($node['_type'] ?? '') === 'page'; })),
272 'count_folders' => count(array_filter($flat, function($node) { return ($node['_type'] ?? '') === 'folder'; })),
273 );
274 }
275
276 private function render_page($id) {
277 $id = (int)$id;
278 if ($id <= 0) return '<div class="dbx-cms-empty">Bitte eine Seite im Content Tree waehlen.</div>';
279 $renderer = dbx()->get_include_obj('dbxContentRenderer', 'dbxContent');
280 return $renderer->render($id);
281 }
282
283 private function render_view() {
284 $tpl = dbx()->get_system_obj('dbxTPL');
285 $root = $this->root_id();
286 $cid = (int)dbx()->get_modul_var('cid', 0, 'int');
287 if (!$cid) $cid = (int)dbx()->get_modul_var('dbx_cid', 0, 'int');
289 $initial_content = $cid > 0
290 ? $this->render_page($cid)
291 : '<div class="dbx-cms-empty">Bitte eine Seite im Content Tree waehlen.</div>';
292
293 if (!$this->needsCmsRuntime()) {
294 return $this->render_frontend_view($cid, $initial_content);
295 }
296
297 $i = dbx()->next_id();
298 $dataDbx = 'lib=cms|mode=view|id=dbx_content_tree_' . $i;
299 if ($isCms) {
300 $dataDbx .= '|tree=' . dbx()->esc($this->base_url('cms', array('dbx_run2' => 'tree', 'root' => $root)));
301 }
302 $dataDbx .= '|viewpage=' . dbx()->esc($this->base_url('cms', array('dbx_run2' => 'page', 'root' => $root)));
303 $dataDbx .= '|cid=' . $cid;
304
305 $panelAttrs = 'data-cms-initial-page-loaded="' . ($cid > 0 ? '1' : '0') . '" data-dbx="' . $dataDbx . '"';
306 $frameTpl = $isCms ? 'content-view-frame-cms' : 'content-view-frame-content';
307 $viewFrame = $tpl->get_tpl('dbxContent|' . $frameTpl, array(
308 'initial_content' => $initial_content,
309 'i' => $i,
310 'cms_tree_search' => dbx()->search_html(dbx()->search_defaults(array(
311 'title' => 'Tree durchsuchen',
312 'extra_attrs' => 'data-cms-search',
313 'data_role' => '',
314 ))),
315 ));
316
317 $data = array_merge(
318 $this->moduleFrameReplaces(
319 $this->page_title($cid),
320 $i,
321 $panelAttrs,
322 $this->adminEditorBarHtml(),
323 $isCms ? 'Content Tree' : '',
324 $this->treeToggleBarHtml()
325 ),
326 array(
327 'frame_panel_class' => 'dbx-cms dbx-cms-view ' . ($isCms ? 'dbx-content-tree-view' : 'dbx-content-show') . ' dbxReport',
328 'frame_body_class' => $isCms ? 'dbx-content-tree-body' : 'dbx-content-show-body',
329 'i' => $i,
330 'cid' => (string)$cid,
331 'initial_loaded' => $cid > 0 ? '1' : '0',
332 'initial_content' => $initial_content,
333 'view_frame' => $viewFrame,
334 'tree_url' => $isCms ? dbx()->esc($this->base_url('cms', array('dbx_run2' => 'tree', 'root' => $root))) : '',
335 'view_page_url' => dbx()->esc($this->base_url('cms', array('dbx_run2' => 'page', 'root' => $root))),
336 )
337 );
338 return $tpl->get_tpl('dbxContent|content-view', $data);
339 }
340
341 private function tree_json() {
343 dbx()->json_response(array('ok' => 0, 'msg' => 'Content Tree ist im Modus content deaktiviert.'), true);
344 }
345
346 dbx()->json_response(array('ok' => 1) + $this->tree(), true);
347 }
348
349 private function page_json() {
351 dbx()->json_response(array('ok' => 0, 'msg' => 'Content Tree ist im Modus content deaktiviert.'), true);
352 }
353
354 $id = (int)dbx()->get_modul_var('id', 0, 'int');
355 $db = dbx()->get_system_obj('dbxDB');
356 $row = $id > 0 ? $db->select1(dbxContentLng::ddContent(), $id, 'id,title', 0) : array();
357 dbx()->json_response(array(
358 'ok' => 1,
359 'id' => $id,
360 'title' => is_array($row) ? (string)($row['title'] ?? '') : '',
361 'html' => $this->render_page($id),
362 ), true);
363 }
364
365 public function run($action = 'view') {
366 switch ($action) {
367 case 'tree_view':
368 return $this->tree_json();
369 case 'tree_page':
370 return $this->page_json();
371 case 'view':
372 default:
373 return $this->render_view();
374 }
375 }
376}
377
378?>
$table['server']
Definition .dd.php:6
static ddFolder(string $lng='')
static ddContent(string $lng='')
DBX schema administration.
$_SERVER['REQUEST_URI']