dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
export_doxygen_tutorials_de.php
Go to the documentation of this file.
1<?php
2declare(strict_types=1);
3
5
6if (PHP_SAPI !== 'cli') {
7 fwrite(STDERR, "Dieses Werkzeug darf nur auf der Kommandozeile laufen.\n");
8 exit(1);
9}
10
11$write = in_array('--write', $argv, true);
12$check = in_array('--check', $argv, true);
13if ($write && $check) {
14 fwrite(STDERR, "--write und --check dürfen nicht gemeinsam verwendet werden.\n");
15 exit(1);
16}
17
18$root = dirname(__DIR__, 4);
19chdir($root);
20
21$_SERVER['REQUEST_URI'] = '/dbxapp/';
22$_SERVER['HTTP_HOST'] = 'localhost';
23$_SERVER['HTTPS'] = 'on';
24$_SERVER['SCRIPT_NAME'] = '/dbxapp/index.php';
25
26define('dbxSystem', 'dbxWebApp');
27define('dbxRunAsAdmin', 1);
28
29require $root . '/dbx/vendor/autoload.php';
30require_once $root . '/dbx/include/dbxKernel.php';
31require_once $root . '/dbx/modules/dbxContent/include/dbxContent_bootstrap_sync.php';
32
36function dbxDoxygenTutorialLabel(string $permalink): string {
37 $token = strtolower(trim($permalink));
38 $token = preg_replace('/[^a-z0-9]+/', '_', $token);
39 $token = trim((string)$token, '_');
40 return 'dbxcontent_tutorial_' . ($token !== '' ? $token : 'seite');
41}
42
46function dbxDoxygenNormalizeBrand(string $value): string {
47 return str_replace(
48 array('dbXApp', 'dbXapp', 'DBXapp', 'DBXApp'),
49 'dbxapp',
50 $value
51 );
52}
53
58function dbxDoxygenNormalizeDisplayText(string $value): string {
60 return str_replace(
61 array(' fuer ', 'Gefuehrter', 'gefuehrter'),
62 array(' für ', 'Geführter', 'geführter'),
63 $value
64 );
65}
66
67function dbxDoxygenHtml(string $value): string {
68 return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
69}
70
71function dbxDoxygenSafeFileToken(string $value): string {
72 $value = strtolower(trim($value));
73 $value = preg_replace('/[^a-z0-9._-]+/', '-', $value);
74 return trim((string)$value, '.-');
75}
76
77function dbxDoxygenMediaAssetName(array $row): string {
78 $path = trim((string)($row['file_path'] ?? ''));
79 $extension = strtolower((string)pathinfo($path, PATHINFO_EXTENSION));
80 if (!preg_match('/^[a-z0-9]{2,8}$/', $extension)) {
81 $extension = 'bin';
82 }
83 $title = dbxDoxygenSafeFileToken((string)($row['title'] ?? ''));
84 if ($title === '') {
85 $title = 'medium';
86 }
87 return 'dbxcontent-media-' . (int)($row['id'] ?? 0) . '-' . $title . '.' . $extension;
88}
89
93function dbxDoxygenMediaRow($db, int $mediaId, array &$cache): array {
94 if ($mediaId <= 0) {
95 return array();
96 }
97 if (isset($cache[$mediaId])) {
98 return $cache[$mediaId];
99 }
100
101 $row = $db->select1(
102 'dbxMedia',
103 $mediaId,
104 'id,active,title,alt,caption,file_name,file_path,mime,size,width,height',
105 0
106 );
107 if (!is_array($row)
108 || (int)($row['id'] ?? 0) !== $mediaId
109 || (int)($row['active'] ?? 0) !== 1) {
110 $row = array();
111 }
112 $cache[$mediaId] = $row;
113 return $row;
114}
115
120 $db,
121 int $mediaId,
122 array &$mediaCache,
123 array &$assets,
124 array &$missingMedia,
125 string $fileRoot,
126 string $assetDir
127): string {
129 if (!$row) {
130 $missingMedia[$mediaId] = 'Datenbankeintrag fehlt oder ist inaktiv';
131 return '';
132 }
133
134 $relative = str_replace('\\', '/', trim((string)($row['file_path'] ?? '')));
135 $relative = ltrim($relative, '/');
136 $source = rtrim($fileRoot, '/\\') . DIRECTORY_SEPARATOR
137 . str_replace('/', DIRECTORY_SEPARATOR, $relative);
138 $sourceReal = realpath($source);
139 $fileRootReal = realpath($fileRoot);
140 if ($sourceReal === false
141 || $fileRootReal === false
142 || strpos(strtolower($sourceReal), strtolower(rtrim($fileRootReal, '/\\') . DIRECTORY_SEPARATOR)) !== 0
143 || !is_file($sourceReal)) {
144 $missingMedia[$mediaId] = $relative !== '' ? $relative : 'Dateipfad fehlt';
145 return '';
146 }
147
148 $assetName = dbxDoxygenMediaAssetName($row);
149 $assets[$assetName] = array(
150 'source' => $sourceReal,
151 'target' => $assetDir . DIRECTORY_SEPARATOR . $assetName,
152 'row' => $row,
153 );
154 return $assetName;
155}
156
162 string $html,
163 $db,
164 array $labelMap,
165 array &$inlineMedia,
166 array &$mediaCache,
167 array &$assets,
168 array &$missingMedia,
169 string $fileRoot,
170 string $assetDir
171): string {
173 $html = preg_replace('#<script\b[^>]*>.*?</script>#is', '', $html);
174 $html = preg_replace('#<style\b[^>]*>.*?</style>#is', '', (string)$html);
175 $html = preg_replace('/\s+on[a-z]+\s*=\s*(["\']).*?\1/is', '', (string)$html);
176 $html = preg_replace('#<h1\b([^>]*)>(.*?)</h1>#is', '<h2$1>$2</h2>', (string)$html);
177
178 $html = preg_replace_callback(
179 '#(<img\b[^>]*\bsrc=)(["\'])([^"\']+)\2#i',
180 static function(array $match) use (
181 $db,
182 &$inlineMedia,
184 &$assets,
186 $fileRoot,
188 ): string {
189 $src = html_entity_decode((string)$match[3], ENT_QUOTES | ENT_HTML5, 'UTF-8');
190 if (!preg_match('/(?:[?&]|\b)dbx_mid=([0-9]+)/i', $src, $idMatch)) {
191 return $match[0];
192 }
193 $mediaId = (int)$idMatch[1];
194 $assetName = dbxDoxygenRegisterMedia(
195 $db,
196 $mediaId,
198 $assets,
200 $fileRoot,
202 );
203 if ($assetName === '') {
204 return $match[0];
205 }
206 $inlineMedia[$mediaId] = 1;
207 return $match[1] . $match[2] . $assetName . $match[2];
208 },
209 (string)$html
210 );
211
212 $html = preg_replace_callback(
213 '#<a\b([^>]*)\bhref=(["\'])([^"\']+)\2([^>]*)>(.*?)</a>#is',
214 static function(array $match) use ($labelMap): string {
215 $href = html_entity_decode(trim((string)$match[3]), ENT_QUOTES | ENT_HTML5, 'UTF-8');
216 $permalink = trim((string)parse_url($href, PHP_URL_PATH), '/');
217 if (isset($labelMap[$permalink])) {
218 $text = trim(preg_replace('/\s+/u', ' ', strip_tags((string)$match[5])));
219 return '<a href="' . dbxDoxygenHtml($labelMap[$permalink]) . '.html">'
221 . '</a>';
222 }
223 if (strpos($href, '?dbx_') === 0 || strpos($href, 'index.php?dbx_') === 0) {
224 $text = trim(preg_replace('/\s+/u', ' ', strip_tags((string)$match[5])));
225 return '<span class="dbx-runtime-route"><strong>'
227 . '</strong><code>' . dbxDoxygenHtml($href) . '</code></span>';
228 }
229 return $match[0];
230 },
231 (string)$html
232 );
233
234 $html = preg_replace_callback(
235 '#\‍[modul=([^\‍]]+)\‍](.*?)\‍[/modul\‍]#is',
236 static function(array $match): string {
237 return '<pre class="dbx-runtime-example"><code>'
238 . dbxDoxygenHtml($match[0])
239 . '</code></pre>';
240 },
241 (string)$html
242 );
243
244 return trim((string)$html);
245}
246
247function dbxDoxygenFigure(array $media, string $assetName): string {
248 $alt = trim((string)($media['alt'] ?? ''));
249 if ($alt === '') {
250 $alt = trim((string)($media['title'] ?? 'Screenshot'));
251 }
252 $caption = trim((string)($media['caption'] ?? ''));
253 if ($caption === '') {
254 $caption = trim((string)($media['title'] ?? ''));
255 }
256
257 $caption = dbxDoxygenNormalizeDisplayText($caption !== '' ? $caption : $alt);
258 $caption = trim(preg_replace('/\s+/u', ' ', strip_tags($caption)));
259 $caption = str_replace(array('\\', '"'), array('\\\\', "'"), $caption);
260 return '@image html ' . $assetName . ($caption !== '' ? ' "' . $caption . '"' : '');
261}
262
263$db = dbx()->get_system_obj('dbxDB');
264if (!is_object($db) || !$db->connect_db_server('dbx|dbxContent.db3')) {
265 fwrite(STDERR, "Die Content-Datenbank konnte nicht über dbxDB verbunden werden.\n");
266 exit(1);
267}
268
269$contentDd = dbxContentLng::ddContent('de');
270$pages = $db->select(
272 'folder = 15 AND activ = 1',
273 'id,folder,sorter,title,permalink,description,content,update_date',
274 'sorter,id',
275 'ASC',
276 '',
277 0,
278 0,
279 0
280);
281if (!is_array($pages) || !$pages) {
282 fwrite(STDERR, "Im deutschen Tutorial-Ordner wurden keine aktiven Seiten gefunden.\n");
283 exit(1);
284}
285
286$outputDir = $root . '/docs/generated/tutorials';
287$assetDir = $outputDir . '/assets';
288$fileRoot = dbx()->get_file_dir();
289$labelMap = array();
290foreach ($pages as $page) {
291 $permalink = trim((string)($page['permalink'] ?? ''));
292 if ($permalink !== '') {
293 $labelMap[$permalink] = dbxDoxygenTutorialLabel($permalink);
294 }
295}
296
297$documents = array();
298$assets = array();
299$mediaCache = array();
304
305foreach ($pages as $page) {
306 $id = (int)($page['id'] ?? 0);
307 $permalink = trim((string)($page['permalink'] ?? ''));
308 if ($id <= 0 || $permalink === '' || !isset($labelMap[$permalink])) {
309 continue;
310 }
311
312 $inlineMedia = array();
314 (string)($page['content'] ?? ''),
315 $db,
316 $labelMap,
317 $inlineMedia,
319 $assets,
321 $fileRoot,
323 );
324
325 $usageRows = $db->select(
326 'dbxMediaUsage',
327 'content_id = ' . $id . ' AND active = 1',
328 'id,media_id,slot,sorter',
329 'slot,sorter,id',
330 'ASC',
331 '',
332 0,
333 0,
334 0
335 );
336 $gallery = array();
337 $seenUsage = array();
338 foreach (is_array($usageRows) ? $usageRows : array() as $usage) {
339 $usageLinks++;
340 $mediaId = (int)($usage['media_id'] ?? 0);
341 if ($mediaId <= 0 || isset($seenUsage[$mediaId])) {
342 continue;
343 }
344 $seenUsage[$mediaId] = 1;
346 if (isset($inlineMedia[$mediaId])) {
348 continue;
349 }
350 $assetName = dbxDoxygenRegisterMedia(
351 $db,
352 $mediaId,
354 $assets,
356 $fileRoot,
358 );
360 if ($assetName === '' || !$media || strpos(strtolower((string)($media['mime'] ?? '')), 'image/') !== 0) {
361 continue;
362 }
363 $gallery[] = dbxDoxygenFigure($media, $assetName);
365 }
366
367 $title = dbxDoxygenNormalizeDisplayText(trim((string)($page['title'] ?? 'Tutorial')));
368 $description = dbxDoxygenNormalizeDisplayText(trim((string)($page['description'] ?? '')));
369 $label = $labelMap[$permalink];
370 $sorter = dbxDoxygenSafeFileToken((string)($page['sorter'] ?? '9999'));
371 $fileName = ($sorter !== '' ? $sorter : '9999') . '-' . dbxDoxygenSafeFileToken($permalink) . '.dox';
372
373 $lines = array(
374 '';
433 $lines[] = '';
434
435 $documents[$fileName] = implode("\n", $lines);
436}
437
438$stale = array();
441$mode = $write ? 'write' : ($check ? 'check' : 'dry-run');
442
443if ($write) {
444 if (!is_dir($assetDir) && !mkdir($assetDir, 0775, true) && !is_dir($assetDir)) {
445 fwrite(STDERR, "Das Doxygen-Tutorialverzeichnis konnte nicht angelegt werden.\n");
446 exit(1);
447 }
448 foreach (array_merge(
449 glob($outputDir . '/*.md') ?: array(),
450 glob($outputDir . '/*.dox') ?: array()
451 ) as $oldFile) {
452 @unlink($oldFile);
453 }
454 foreach (glob($assetDir . '/dbxcontent-media-*') ?: array() as $oldAsset) {
455 @unlink($oldAsset);
456 }
457 foreach ($documents as $fileName => $content) {
458 if (file_put_contents($outputDir . '/' . $fileName, $content, LOCK_EX) === false) {
459 fwrite(STDERR, "Tutorial konnte nicht geschrieben werden: {$fileName}\n");
460 exit(1);
461 }
462 $written++;
463 }
464 foreach ($assets as $asset) {
465 if (!copy((string)$asset['source'], (string)$asset['target'])) {
466 fwrite(STDERR, "Tutorialmedium konnte nicht kopiert werden: {$asset['source']}\n");
467 exit(1);
468 }
470 }
471}
472
473if ($check) {
474 foreach ($documents as $fileName => $content) {
475 $path = $outputDir . '/' . $fileName;
476 if (!is_file($path) || (string)file_get_contents($path) !== $content) {
477 $stale[] = str_replace('\\', '/', substr($path, strlen($root) + 1));
478 }
479 }
480 foreach ($assets as $assetName => $asset) {
481 $target = (string)$asset['target'];
482 $source = (string)$asset['source'];
483 if (!is_file($target)
484 || filesize($target) !== filesize($source)
485 || hash_file('sha256', $target) !== hash_file('sha256', $source)) {
486 $stale[] = 'docs/generated/tutorials/assets/' . $assetName;
487 }
488 }
489}
490
491$result = array(
492 'mode' => $mode,
493 'language' => 'de',
494 'source_dd' => $contentDd,
495 'tutorial_pages' => count($documents),
496 'media_usage_links' => $usageLinks,
497 'unique_page_media_links' => $uniqueUsageLinks,
498 'covered_page_media_links' => $coveredUsageLinks,
499 'unique_media_assets' => count($assets),
500 'missing_media' => $missingMedia,
501 'written_pages' => $written,
502 'copied_assets' => $copiedAssets,
503 'stale_files' => $stale,
504);
505echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
506
507if ($missingMedia || ($check && $stale)) {
508 exit(1);
509}
parse_url($data)
Zerlegt URL-/Parameterdaten in einen Array.
Definition dbxApi.php:2416
$_SERVER['REQUEST_METHOD']
if(strpos($mainRule, 'dbx-page-gears-v1.svg')===false||strpos($mainRule, 'background-repeat:no-repeat, no-repeat, repeat !important')===false||strpos($mainRule, 'background-size:100vw auto')===false) $assets
if(!defined( 'IMG_WEBP')) define( 'IMG_WEBP'
dbxDoxygenFigure(array $media, string $assetName)
dbxDoxygenMediaRow($db, int $mediaId, array &$cache)
Liefert einen Medien-Datensatz ausschließlich über dbxDB.
dbxDoxygenMediaAssetName(array $row)
foreach($pages as $page) $stale
dbxDoxygenRegisterMedia( $db, int $mediaId, array &$mediaCache, array &$assets, array &$missingMedia, string $fileRoot, string $assetDir)
Registriert eine lokale Mediendatei für den generierten Doxygen-Bestand.
dbxDoxygenNormalizeBrand(string $value)
Vereinheitlicht ausschließlich die Produktbezeichnung in der Exportkopie.
dbxDoxygenNormalizeDisplayText(string $value)
Korrigiert bekannte alte ASCII-Umschriften in sichtbaren Metadaten.
dbxDoxygenHtml(string $value)
dbxDoxygenTutorialLabel(string $permalink)
Erzeugt einen stabilen Doxygen-Bezeichner aus einem Permalink.
foreach($pages as $page) $documents
dbxDoxygenPrepareContent(string $html, $db, array $labelMap, array &$inlineMedia, array &$mediaCache, array &$assets, array &$missingMedia, string $fileRoot, string $assetDir)
Entfernt aktive Browserbestandteile, normalisiert Überschriften und wandelt dbxContent-interne Links ...
dbxDoxygenSafeFileToken(string $value)
if(!is_array($pages)||! $pages) $outputDir
if(PHP_SAPI !=='cli') $write
exit
Definition index.php:146
DBX schema administration.
if($cinematic===''||!str_contains($cinematic, 'data-dbx-cinema')) $page
for( $step=0;$step< 1000;$step++) if(($schema['status'] ?? '') !=='finished') $media