dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
dbxKi.class.php
Go to the documentation of this file.
1<?php
2namespace dbx\dbxKi;
3
4require_once dirname(__DIR__) . '/dbxContent/include/dbxContent_bootstrap_sync.php';
5
6class dbxKi {
7
8 private function cms() {
9 return dbx()->get_include_obj('dbxKiCmsService', 'dbxKi');
10 }
11
12 private function bundle() {
13 return dbx()->get_include_obj('dbxKiBundleService', 'dbxKi');
14 }
15
16 private function briefing() {
17 return dbx()->get_include_obj('dbxKiBriefingService', 'dbxKi');
18 }
19
20 private function moduleBriefing() {
21 return dbx()->get_include_obj('dbxKiModuleBriefingService', 'dbxKi');
22 }
23
24 private function design() {
25 return dbx()->get_include_obj('dbxKiDesignService', 'dbxKi');
26 }
27
28 private function help() {
29 return dbx()->get_include_obj('dbxKiHelp', 'dbxKi');
30 }
31
32 private function provision() {
33 require_once __DIR__ . '/include/dbxKiCmsHelpProvision.class.php';
35 }
36
37 private function html_start(): string {
38 require_once __DIR__ . '/include/dbxKiCmsHelpProvision.class.php';
40 $anleitungUrl = dbxKiCmsHelpProvision::pageUrl();
41 $briefing = '?dbx_modul=dbxKi&dbx_run1=briefing';
42 $bundle = '?dbx_modul=dbxKi&dbx_run1=bundle';
43 $design = '?dbx_modul=dbxKi&dbx_run1=briefing_design';
44 $syncAll = '?dbx_modul=dbxKi&dbx_run1=translation_sync_all';
45 $api = '?dbx_modul=dbxKi&dbx_run1=api';
46
47 return '<div class="container py-4">'
48 . '<h1>dbxKi</h1>'
49 . '<p>Formular-basierte KI-Auftraege fuer das Content-CMS.</p>'
50 . '<div class="d-flex flex-wrap gap-2 mb-3">'
51 . '<a class="btn btn-primary" href="' . htmlspecialchars($briefing, ENT_QUOTES, 'UTF-8') . '">KI-Auftrag starten</a>'
52 . '<a class="btn btn-outline-primary" href="' . htmlspecialchars($syncAll, ENT_QUOTES, 'UTF-8') . '">Sprache komplett uebersetzen</a>'
53 . '<a class="btn btn-outline-primary" href="' . htmlspecialchars($bundle, ENT_QUOTES, 'UTF-8') . '">Bundle importieren</a>'
54 . '<a class="btn btn-outline-primary" href="' . htmlspecialchars($design, ENT_QUOTES, 'UTF-8') . '">Design entwickeln</a>'
55 . '<a class="btn btn-outline-secondary" href="' . htmlspecialchars($anleitungUrl, ENT_QUOTES, 'UTF-8') . '">Anleitung</a>'
56 . '</div>'
57 . '<p class="small text-muted">Ablauf: Formular → ZIP an ChatGPT → fertige ZIP importieren und ausfuehren.</p>'
58 . '<p><strong>API:</strong> <code>' . htmlspecialchars($api, ENT_QUOTES, 'UTF-8') . '</code></p>'
59 . '</div>';
60 }
61
62 private function esc($value): string {
63 return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
64 }
65
66 private function language_options(string $selected): string {
67 $html = '';
68 foreach (\dbx\dbxContent\dbxContentLngSync::accessibleLngs() as $lng) {
69 $sel = $lng === $selected ? ' selected' : '';
70 $html .= '<option value="' . $this->esc($lng) . '"' . $sel . '>' . $this->esc(strtoupper($lng)) . '</option>';
71 }
72 return $html;
73 }
74
75 private function target_language_checkboxes(string $sourceLng, array $selected): string {
76 $html = '';
77 foreach (\dbx\dbxContent\dbxContentLngSync::accessibleLngs() as $lng) {
78 if ($lng === $sourceLng) {
79 continue;
80 }
81 $checked = in_array($lng, $selected, true) ? ' checked' : '';
82 $html .= '<label class="form-check form-check-inline">'
83 . '<input class="form-check-input" type="checkbox" name="target_lngs[]" value="' . $this->esc($lng) . '"' . $checked . '>'
84 . '<span class="form-check-label">' . $this->esc(strtoupper($lng)) . '</span>'
85 . '</label>';
86 }
87 return $html !== '' ? $html : '<span class="text-muted">Keine weitere aktive Sprache vorhanden.</span>';
88 }
89
90 private function translation_sync_params_from_request(): array {
91 $sourceLng = strtolower(trim((string)dbx()->get_request_var('source_lng', \dbx\dbxContent\dbxContentLngSync::masterLng(), '*')));
92 $targets = dbx()->get_request_var('target_lngs', array(), '*');
93 if (is_string($targets)) {
94 $targets = array($targets);
95 }
96 if (!is_array($targets)) {
97 $targets = array();
98 }
99 return array(
100 'source_lng' => $sourceLng,
101 'target_lngs' => array_values(array_filter(array_map(static function($lng) {
102 return strtolower(trim((string)$lng));
103 }, $targets))),
104 'root_folder_id' => max(0, (int)dbx()->get_request_var('root_folder_id', 0, '*')),
105 'update_existing' => !array_key_exists('sync_mode', $_REQUEST) || dbx()->get_request_var('update_existing', '0', '*') === '1' ? 1 : 0,
106 'skip_manual' => dbx()->get_request_var('skip_manual', '0', '*') === '1' ? 1 : 0,
107 'copy_media' => !array_key_exists('sync_mode', $_REQUEST) || dbx()->get_request_var('copy_media', '0', '*') === '1' ? 1 : 0,
108 'replace_media_usage' => dbx()->get_request_var('replace_media_usage', '0', '*') === '1' ? 1 : 0,
109 );
110 }
111
123 private function translation_sync_form(array $replacements = array()) {
124 $form = dbx()->get_system_obj('dbxForm');
125 $form->init('ki-translation-sync-all', 'ki-translation-sync-all');
126 $form->_action = '?dbx_modul=dbxKi&dbx_run1=translation_sync_all';
127 $form->_msg_info = '';
128 foreach ($replacements as $key => $value) {
129 $form->add_rep((string)$key, $value);
130 }
131 return $form;
132 }
133
134 private function render_translation_sync_all(): string {
135 $params = $this->translation_sync_params_from_request();
136 $form = $this->translation_sync_form();
137 $hasPost = array_key_exists('sync_mode', $_POST);
138 $hasSubmitted = (bool)$form->submit();
139 if (!$hasSubmitted && !count($params['target_lngs'])) {
140 foreach (\dbx\dbxContent\dbxContentLngSync::accessibleLngs() as $lng) {
141 if ($lng !== $params['source_lng']) {
142 $params['target_lngs'][] = $lng;
143 }
144 }
145 }
146
147 $mode = strtolower(trim((string)dbx()->get_request_var('sync_mode', '', '*')));
148 $resultHtml = '';
149 if ($hasPost && !$hasSubmitted) {
150 $resultHtml = '<div class="alert alert-danger">Ungueltiger oder abgelaufener Formular-Token.</div>';
151 } elseif ($hasSubmitted && ($mode === 'preview' || $mode === 'execute')) {
152 try {
153 $plan = $this->cms()->bundleBuildPlan('translation.sync_all', $params);
154 if ($mode === 'execute') {
155 $result = $this->cms()->bundleExecutePlan('translation.sync_all', $params, $plan);
156 $resultHtml = $this->translation_sync_result_html($result, true);
157 } else {
158 $resultHtml = $this->translation_sync_plan_html($plan);
159 }
160 } catch (\Throwable $e) {
161 $resultHtml = '<div class="alert alert-danger">' . $this->esc($e->getMessage()) . '</div>';
162 }
163 }
164
165 $replacements = array_merge(array(
166 'action' => '?dbx_modul=dbxKi&amp;dbx_run1=translation_sync_all',
167 'language_options' => $this->language_options($params['source_lng']),
168 'target_language_checkboxes' => $this->target_language_checkboxes($params['source_lng'], $params['target_lngs']),
169 'root_folder_id' => $this->esc((string)$params['root_folder_id']),
170 'update_existing_checked' => (int)$params['update_existing'] === 1 ? 'checked' : '',
171 'skip_manual_checked' => (int)$params['skip_manual'] === 1 ? 'checked' : '',
172 'copy_media_checked' => (int)$params['copy_media'] === 1 ? 'checked' : '',
173 'replace_media_usage_checked' => (int)$params['replace_media_usage'] === 1 ? 'checked' : '',
174 'result_html' => $resultHtml,
175 ), $this->help()->moduleBarTemplateData(
176 'translation_sync_all',
177 '<a class="btn btn-outline-secondary btn-sm" href="?dbx_modul=dbxKi"><i class="bi bi-arrow-left"></i> Zurueck</a>'
178 ));
179
180 foreach ($replacements as $key => $value) {
181 $form->add_rep((string)$key, $value);
182 }
183 return $form->run();
184 }
185
186 private function translation_sync_plan_html(array $plan): string {
187 $counts = is_array($plan['counts'] ?? null) ? $plan['counts'] : array();
188 $targets = is_array($plan['target_lngs'] ?? null) ? implode(', ', array_map('strtoupper', $plan['target_lngs'])) : '';
189 return '<div class="alert alert-info">'
190 . '<strong>Vorschau:</strong> '
191 . $this->esc((string)($counts['folders'] ?? 0)) . ' Ordner und '
192 . $this->esc((string)($counts['pages'] ?? 0)) . ' Seiten von '
193 . $this->esc(strtoupper((string)($plan['source_lng'] ?? ''))) . ' nach '
194 . $this->esc($targets) . '. Provider: '
195 . $this->esc((string)($plan['provider'] ?? '')) . '.'
196 . '</div>';
197 }
198
199 private function translation_sync_result_html(array $result, bool $executed): string {
200 $folders = is_array($result['folders'] ?? null) ? $result['folders'] : array();
201 $pages = is_array($result['pages'] ?? null) ? $result['pages'] : array();
202 $errors = is_array($result['errors'] ?? null) ? $result['errors'] : array();
203 $warnings = is_array($result['warnings'] ?? null) ? $result['warnings'] : array();
204 $class = count($errors) ? 'alert-warning' : 'alert-success';
205 $html = '<div class="alert ' . $class . '"><strong>' . ($executed ? 'Ausgefuehrt.' : 'Ergebnis.') . '</strong> '
206 . 'Ordner: ' . count($folders['created'] ?? array()) . ' neu, ' . count($folders['updated'] ?? array()) . ' aktualisiert. '
207 . 'Seiten: ' . count($pages['created'] ?? array()) . ' neu, ' . count($pages['updated'] ?? array()) . ' aktualisiert. '
208 . 'Medienzuordnungen: ' . (int)($result['media_copied'] ?? 0) . '.</div>';
209 if (count($errors)) {
210 $html .= '<div class="card p-3 mb-3"><h2 class="h6">Fehler</h2><ul class="mb-0">';
211 foreach ($errors as $error) {
212 $html .= '<li>' . $this->esc($error) . '</li>';
213 }
214 $html .= '</ul></div>';
215 }
216 if (count($warnings)) {
217 $html .= '<div class="card p-3 mb-3"><h2 class="h6">Hinweise</h2><ul class="mb-0">';
218 foreach ($warnings as $warning) {
219 $msg = is_array($warning) ? (($warning['message'] ?? '') . ' ' . ($warning['lng'] ?? '')) : (string)$warning;
220 $html .= '<li>' . $this->esc(trim($msg)) . '</li>';
221 }
222 $html .= '</ul></div>';
223 }
224 return $html;
225 }
226
227 private function html_provision_result(array $result): string {
228 $ok = empty($result['errors']);
229 $class = $ok ? 'alert-success' : 'alert-danger';
230 $msg = $ok ? 'CMS-Anleitung provisioniert.' : 'Provision fehlgeschlagen.';
232 $back = '?dbx_modul=dbxKi';
233
234 return '<div class="container py-4">'
235 . '<div class="alert ' . $class . '">' . htmlspecialchars($msg, ENT_QUOTES, 'UTF-8') . '</div>'
236 . '<pre class="bg-light p-3 rounded">' . htmlspecialchars(json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8') . '</pre>'
237 . '<div class="d-flex flex-wrap gap-2">'
238 . '<a class="btn btn-primary" href="' . htmlspecialchars($pageUrl, ENT_QUOTES, 'UTF-8') . '">Zur Anleitung</a>'
239 . '<a class="btn btn-outline-secondary" href="' . htmlspecialchars($back, ENT_QUOTES, 'UTF-8') . '">dbxKi Uebersicht</a>'
240 . '</div></div>';
241 }
242
243 private function html_error(string $message, string $backUrl): string {
244 return '<div class="container py-4"><div class="alert alert-danger">'
245 . htmlspecialchars($message, ENT_QUOTES, 'UTF-8')
246 . '</div><p><a class="btn btn-secondary" href="' . htmlspecialchars($backUrl, ENT_QUOTES, 'UTF-8') . '">Zurueck</a></p></div>';
247 }
248
249 public function run($action = '') {
250 if ($action === '') {
251 $action = dbx()->get_modul_var('dbx_run1', 'start', 'parameter');
252 }
253
254 switch ($action) {
255 case 'api':
256 case 'describe':
257 case 'preview':
258 case 'execute':
259 $this->cms()->handle($action);
260 return '';
261
262 case 'briefing':
263 return $this->briefing()->renderHub();
264
265 case 'briefing_module':
266 return $this->moduleBriefing()->renderBriefing();
267
268 case 'briefing_module_export':
269 $this->moduleBriefing()->handleExport();
270 return '';
271
272 case 'briefing_design':
273 return $this->design()->renderBriefing();
274
275 case 'briefing_design_export':
276 try {
277 $this->design()->handleExport();
278 } catch (\Throwable $e) {
279 dbx()->sys_msg('error', 'dbxKi', 'briefing_design_export', 'Design-Export fehlgeschlagen', $e->getMessage());
280 return $this->html_error($e->getMessage(), '?dbx_modul=dbxKi&dbx_run1=briefing_design');
281 }
282 return '';
283
284 case 'design_bundle_import':
285 return $this->design()->handleImport();
286
287 case 'design_bundle_apply':
288 return $this->design()->handleApply();
289
290 case 'module_bundle':
291 return $this->moduleBriefing()->renderBundleStart();
292
293 case 'module_bundle_import':
294 return $this->moduleBriefing()->handleBundleImport();
295
296 case 'module_api':
297 $this->moduleBriefing()->handleApi();
298 return '';
299
300 case 'briefing_page_create':
301 return $this->briefing()->renderPageCreateForm();
302
303 case 'briefing_page_update':
304 return $this->briefing()->renderPageUpdateForm();
305
306 case 'briefing_page_update_preview':
307 $this->briefing()->handlePageUpdatePreviewJson();
308 return '';
309
310 case 'briefing_page_translate':
311 return $this->briefing()->renderPageTranslateForm();
312
313 case 'translation_sync_all':
314 return $this->render_translation_sync_all();
315
316 case 'briefing_styles':
317 return $this->briefing()->renderStylesAdmin();
318
319 case 'briefing_styles_save':
320 return $this->briefing()->handleStylesSave();
321
322 case 'briefing_styles_reset':
323 return $this->briefing()->handleStylesReset();
324
325 case 'briefing_export':
326 try {
327 $this->briefing()->handleExport();
328 } catch (\Throwable $e) {
329 dbx()->sys_msg('error', 'dbxKi', 'briefing_export', 'Export fehlgeschlagen', $e->getMessage());
330 $recipe = strtolower(trim((string) dbx()->get_request_var('recipe', '', '*')));
331 return $this->html_error($e->getMessage(), $this->briefing()->exportBackUrl($recipe));
332 }
333 return '';
334
335 case 'bundle':
336 return $this->bundle()->renderStartPage();
337
338 case 'bundle_import':
339 return $this->bundle()->handleImport();
340
341 case 'bundle_process':
342 return $this->bundle()->handleProcess();
343
344 case 'bundle_export':
345 $this->bundle()->handleExport();
346 return '';
347
348 case 'bundle_describe':
349 $this->bundle()->handleDescribeJson();
350 return '';
351
352 case 'help':
353 return $this->help()->renderHelpWindow();
354
355 case 'provision_anleitung':
356 require_once __DIR__ . '/include/dbxKiCmsHelpProvision.class.php';
357 $result = $this->provision();
358 if (empty($result['errors'])) {
359 $config = dbx()->get_config('dbxKi');
360 if (!is_array($config)) {
361 $config = array();
362 }
364 dbx()->set_config('dbxKi', $config);
365 }
366 return $this->html_provision_result($result);
367
368 case 'start':
369 default:
370 require_once __DIR__ . '/include/dbxKiCmsHelpProvision.class.php';
371 return $this->html_start();
372 }
373 }
374}
375
376?>
run($action='')
if($resolved !==$expectedBase . 'files/test/') $config
foreach($rows as $row) $targets
if(trim($second) !=='second') $design
DBX schema administration.