dbxapp 4.1.3
CMS, Shop, Workflows und modulare Geschäftsanwendungen
Loading...
Searching...
No Matches
migrate_flat_permalinks.php
Go to the documentation of this file.
1<?php
2declare(strict_types=1);
3
8
9if (PHP_SAPI !== 'cli') {
10 fwrite(STDERR, "Dieses Werkzeug darf nur auf der Kommandozeile laufen.\n");
11 exit(1);
12}
13
14$base = dirname(__DIR__, 4);
15chdir($base);
16$_SERVER['REQUEST_URI'] = '/dbxapp/';
17$_SERVER['HTTP_HOST'] = 'localhost';
18$_SERVER['HTTPS'] = 'on';
19$_SERVER['SCRIPT_NAME'] = '/dbxapp/index.php';
20
21define('dbxSystem', 'dbxWebApp');
22define('dbxRunAsAdmin', 1);
23
24require $base . '/dbx/vendor/autoload.php';
25require_once $base . '/dbx/include/dbxKernel.php';
26require_once $base . '/dbx/modules/dbxContent/include/dbxContent_bootstrap_sync.php';
27require_once $base . '/dbx/modules/dbxAdmin/include/dbxAdminHelp.class.php';
28
29$dbFile = $base . '/dbx/modules/dbx/db/dbxContent.db3';
30if (!is_file($dbFile)) {
31 fwrite(STDERR, "Content-Datenbank nicht gefunden: {$dbFile}\n");
32 exit(1);
33}
34
35$backupDir = dirname($dbFile) . '/backup';
36if (!is_dir($backupDir) && !mkdir($backupDir, 0775, true) && !is_dir($backupDir)) {
37 fwrite(STDERR, "Backup-Verzeichnis konnte nicht angelegt werden.\n");
38 exit(1);
39}
40$backupFile = $backupDir . '/dbxContent-before-flat-permalinks-' . date('Ymd-His') . '.db3';
41if (!copy($dbFile, $backupFile)) {
42 fwrite(STDERR, "Datenbank-Backup konnte nicht erstellt werden.\n");
43 exit(1);
44}
45
46$db = dbx()->get_system_obj('dbxDB');
47if (!is_object($db) || !$db->connect_db_server('dbx|dbxContent.db3')) {
48 fwrite(STDERR, "Content-Datenbank konnte ueber dbxDB nicht verbunden werden.\n");
49 exit(1);
50}
51
52$help = new dbxAdminHelp();
53$helpLegacy = array();
54foreach ($help->topics() as $topic => $meta) {
55 $slug = str_replace('_', '-', strtolower((string)$topic));
56 $canonical = trim((string)($meta['permalink'] ?? ''));
57 if (!dbxContent_permalink::isValid($canonical)) {
58 throw new RuntimeException('Ungueltiger Hilfe-Permalink fuer ' . $topic . ': ' . $canonical);
59 }
60 $helpLegacy['outside/help/' . $slug] = $canonical;
61 $helpLegacy['help/' . $slug] = $canonical;
62}
63
64$languages = dbxContentLngSync::accessibleLngs();
65if ($languages === array()) {
66 $languages = array(dbxContentLngSync::masterLng());
67}
68$transactionDd = dbxContentLng::ddContent((string)$languages[0]);
69$result = array('backup' => $backupFile, 'tables' => array(), 'updated' => 0, 'links' => 0);
70
71if ($db->begin($transactionDd) !== 1) {
72 fwrite(STDERR, "Transaktion konnte nicht gestartet werden.\nBackup: {$backupFile}\n");
73 exit(1);
74}
75
76try {
77 foreach ($languages as $lng) {
78 $dd = dbxContentLng::ddContent((string)$lng);
79 $table = $db->get_dd_table($dd);
80 $rows = $db->select($dd, '', 'id,permalink', 'id', 'ASC', '', 0, 0, 0);
81 if (!is_array($rows)) {
82 continue;
83 }
84
85 $used = array();
86 $changes = array();
87 foreach ($rows as $row) {
88 $id = (int)($row['id'] ?? 0);
89 $old = trim((string)($row['permalink'] ?? ''));
90 $legacyKey = strtolower(trim(str_replace('\\', '/', $old), '/'));
91 if (dbxContent_permalink::isValid($old)) {
92 $candidate = $old;
93 } elseif (isset($helpLegacy[$legacyKey])) {
94 $candidate = $helpLegacy[$legacyKey];
95 } else {
96 $candidate = dbxContent_permalink::canonicalFromLegacy($old);
97 }
98 if ($candidate === '') {
99 $candidate = 'seite-' . $id;
100 }
101
102 $baseCandidate = $candidate;
103 $number = 2;
104 while (isset($used[$candidate]) && $used[$candidate] !== $id) {
105 $suffix = '-' . $number;
106 $candidate = rtrim(substr($baseCandidate, 0, 254 - strlen($suffix)), '-') . $suffix;
107 $number++;
108 }
109 if (!dbxContent_permalink::isValid($candidate)) {
110 throw new RuntimeException("Migration erzeugt ungueltigen Permalink {$candidate} fuer {$table}#{$id}.");
111 }
112 $used[$candidate] = $id;
113
114 if ($candidate !== $old) {
115 if ($db->update($dd, array('permalink' => $candidate), $id, 0) !== 1) {
116 throw new RuntimeException("Permalink konnte nicht aktualisiert werden: {$table}#{$id}.");
117 }
118 $changes[$old] = $candidate;
119 $result['updated']++;
120 }
121 }
122
123 if ($changes !== array()) {
124 uksort($changes, static function(string $left, string $right): int {
125 return strlen($right) <=> strlen($left);
126 });
127 $contentRows = $db->select($dd, '', 'id,content', 'id', 'ASC', '', 0, 0, 0);
128 foreach ((is_array($contentRows) ? $contentRows : array()) as $contentRow) {
129 $before = (string)($contentRow['content'] ?? '');
130 if ($before === '') {
131 continue;
132 }
133 $after = str_replace(array_keys($changes), array_values($changes), $before);
134 if ($after !== $before) {
135 if ($db->update($dd, array('content' => $after), (int)$contentRow['id'], 0) !== 1) {
136 throw new RuntimeException("Content-Links konnten nicht aktualisiert werden: {$table}#{$contentRow['id']}.");
137 }
138 $result['links']++;
139 }
140 }
141 }
142
143 $result['tables'][$table] = array('rows' => count($rows), 'changed' => count($changes));
144 }
145
146 if ($db->commit($transactionDd) !== 1) {
147 throw new RuntimeException('Transaktion konnte nicht abgeschlossen werden.');
148 }
149} catch (Throwable $e) {
150 $db->rollback($transactionDd);
151 fwrite(STDERR, $e->getMessage() . "\nBackup: {$backupFile}\n");
152 exit(1);
153}
154
155echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL;
$table['server']
Definition .dd.php:6
if($updated !==1) $after
$_SERVER['REQUEST_METHOD']
exit
Definition index.php:146
DBX schema administration.