ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilDBUpdate.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
29{
30 protected string $updateMsg;
31 protected Iterator $ctrl_structure_iterator;
32
33 protected string $error;
34 protected string $PATH = "./";
35
36 protected array $filecontent;
37
39 private ?int $custom_updates_file_version = null;
40 private ?bool $custom_updates_info_read = null;
42 private array $custom_updates_content = [];
43
44 public function __construct(protected ilDBInterface $db, protected ?ilIniFile $client_ini = null)
45 {
46 $class_map = require ILIAS_ABSOLUTE_PATH . '/vendor/composer/vendor/composer/autoload_classmap.php';
47 $this->ctrl_structure_iterator = new ilCtrlArrayIterator($class_map);
48 }
49
50 private function execQuery(ilDBInterface $db, string $str): bool
51 {
52 $q = "";
53 $sql = explode("\n", trim($str));
54 foreach ($sql as $i => $statement) {
55 $sql[$i] = trim($statement);
56 if ($statement !== "" && $statement[0] !== "#") {
57 //take line per line, until last char is ";"
58 if (str_ends_with($statement, ";")) {
59 //query is complete
61 $q .= " " . substr($statement, 0, -1);
62 $check = $this->checkQuery($q);
63 if ($check) {
64 $db->query($q);
65 } else {
66 $this->error = (string) $check;
67 return false;
68 }
69 unset($q);
70 } else {
72 $q .= " " . $statement;
73 }
74 }
75 }
76 if (isset($q) && $q !== "") {
77 echo "incomplete_statement: " . $q . "<br>";
78
79 return false;
80 }
81
82 return true;
83 }
84
85 protected function checkQuery(string $q): bool
86 {
87 return true;
88 }
89
91 ?ilCtrlStructureReader &$ilCtrlStructureReader,
93 ): void {
94 global $DIC;
95
96 // TODO: There is currently a huge mixup of globals, $DIC and dependencies, esprecially in setup and during DB-Updates. This leads to many problems. The following core tries to provide the needed dependencies for the dbupdate-script. The code hopefully will change in the future.
97
98 if (isset($GLOBALS['ilCtrlStructureReader'])) {
99 $ilCtrlStructureReader = $GLOBALS['ilCtrlStructureReader'];
100 } elseif ($DIC->offsetExists('ilCtrlStructureReader')) {
101 $ilCtrlStructureReader = $DIC['ilCtrlStructureReader'];
102 } else {
103 $ilCtrlStructureReader = new ilCtrlStructureReader(
104 $this->ctrl_structure_iterator,
106 );
107 $DIC->offsetSet('ilCtrlStructureReader', $ilCtrlStructureReader);
108 }
109
110 $GLOBALS['ilCtrlStructureReader'] = $ilCtrlStructureReader;
111
112 if ($this->client_ini !== null) {
113 $ilCtrlStructureReader->setIniFile($this->client_ini);
114 }
115 $ilDB = $DIC->database();
116 }
117
123 protected function applyUpdateNr(int $nr, bool $custom_update = false): bool
124 {
125 $ilCtrlStructureReader = null;
126 $ilDB = null;
127 $this->initGlobalsRequiredForUpdateSteps($ilCtrlStructureReader, $ilDB);
128
129 reset($this->filecontent);
130
131 //init
132 $i = 0;
133
134 //go through filecontent
135 while (!preg_match("/^<\#" . $nr . ">/", (string) $this->filecontent[$i]) && $i < count($this->filecontent)) {
136 $i++;
137 }
138
139 //update not found
140 if ($i === count($this->filecontent)) {
141 $this->error = 'update_not_found';
142
143 return false;
144 }
145
146 $i++;
147
148 //update found, now extract this update to a new array
149 $update = [];
150 while ($i < count($this->filecontent) && !preg_match("/^<#" . ($nr + 1) . ">/", (string) $this->filecontent[$i])) {
151 $update[] = trim((string) $this->filecontent[$i]);
152 $i++;
153 }
154
155 //now you have the update, now process it
156 $sql = [];
157 $php = [];
158 $mode = 'sql';
159
160 foreach ($update as $row) {
161 if (preg_match("/<\?php/", $row)) {
162 if ($sql !== []) {
163 if ($this->execQuery($this->db, implode("\n", $sql)) === false) {
164 return false;
165 }
166 $sql = [];
167 }
168 $mode = 'php';
169 } elseif (preg_match("/\?>/", $row)) {
170 if ($php !== []) {
171 $code = implode("\n", $php);
172 if (eval($code) === false) {
173 $this->error = 'Parse error: ' . $code;
174
175 return false;
176 }
177 $php = [];
178 }
179 $mode = 'sql';
180 } else {
181 if ($mode === 'sql') {
182 $sql[] = $row;
183 }
184
185 if ($mode === 'php') {
186 $php[] = $row;
187 }
188 }
189 }
190
191 if ($mode === 'sql' && $sql !== [] && $this->execQuery($this->db, implode("\n", $sql)) === false) {
192 $this->error = "dump_error: " . $this->error;
193
194 return false;
195 }
196
197 if ($custom_update) {
198 $this->setCustomUpdatesCurrentVersion($nr);
199 } else {
200 $this->setCurrentVersion($nr);
201 }
202
203 return true;
204 }
205
207 {
208 $this->readCustomUpdatesInfo();
209
210 return $this->custom_updates_current_version;
211 }
212
213 private function setCustomUpdatesCurrentVersion(?int $a_version): void
214 {
215 $this->readCustomUpdatesInfo();
216 $this->custom_updates_setting->set('db_version_custom', (string) $a_version);
217 $this->custom_updates_current_version = $a_version;
218 }
219
220 protected function setCurrentVersion(?int $a_version): void
221 {
222 }
223
225 {
226 $this->readCustomUpdatesInfo();
227
228 return $this->custom_updates_file_version;
229 }
230
231 private function readCustomUpdatesFileVersion(array $a_file_content): int
232 {
233 //go through file content and search for last occurrence of <#x>
234 reset($a_file_content);
235 $regs = [];
236 $version = 0;
237 foreach ($a_file_content as $row) {
238 if (preg_match("/^<#(\\d+)>/", (string) $row, $regs)) {
239 $version = $regs[1];
240 }
241 }
242
243 return (int) $version;
244 }
245
246 private function readCustomUpdatesInfo(bool $a_force = false): void
247 {
248 if ($this->custom_updates_info_read && !$a_force) {
249 return;
250 }
251
252 $this->custom_updates_setting = new ilSetting();
253 $custom_updates_file = $this->PATH . './components/ILIAS/setup_/sql/dbupdate_custom.php';
254 if (is_file($custom_updates_file)) {
255 $this->custom_updates_content = @file($custom_updates_file);
256 $this->custom_updates_current_version = (int) $this->custom_updates_setting->get('db_version_custom', '0');
257 $this->custom_updates_file_version = $this->readCustomUpdatesFileVersion($this->custom_updates_content);
258 }
259 $this->custom_updates_info_read = true;
260 }
261
262 public function applyCustomUpdates(): bool
263 {
264 $ilCtrlStructureReader = null;
265 $ilDB = null;
266 $this->initGlobalsRequiredForUpdateSteps($ilCtrlStructureReader, $ilDB);
267 $this->readCustomUpdatesInfo(true);
268
269 $file_version = $this->getCustomUpdatesFileVersion();
270 $current_version = $this->getCustomUpdatesCurrentVersion();
271 $this->filecontent = $this->custom_updates_content;
272
273 $this->updateMsg = 'no_changes';
274 if ($current_version < $file_version) {
275 $msg = [];
276 for ($i = ($current_version + 1); $i <= $file_version; $i++) {
277 if ($this->applyUpdateNr($i, true) === false) {
278 $msg[] = [
279 'msg' => 'update_error: ' . $this->error,
280 'nr' => $i,
281 ];
282 $this->updateMsg = implode("\n", $msg);
283
284 return false;
285 }
286
287 $msg[] = [
288 'msg' => 'custom_update_applied',
289 'nr' => $i,
290 ];
291 }
292
293 $this->updateMsg = implode("\n", $msg);
294 }
295
296 return true;
297 }
298}
$version
Definition: plugin.php:24
$check
Definition: buildRTE.php:81
error(string $a_errmsg)
Class ilCtrlArrayIterator.
Class ilCtrlStructureCidGenerator.
Class ilCtrlStructureReader is responsible for reading ilCtrl's control structure.
Database Update class.
setCurrentVersion(?int $a_version)
readCustomUpdatesInfo(bool $a_force=false)
getCustomUpdatesCurrentVersion()
readCustomUpdatesFileVersion(array $a_file_content)
int $custom_updates_file_version
__construct(protected ilDBInterface $db, protected ?ilIniFile $client_ini=null)
initGlobalsRequiredForUpdateSteps(?ilCtrlStructureReader &$ilCtrlStructureReader, ?ilDBInterface &$ilDB)
int $custom_updates_current_version
ilSetting $custom_updates_setting
checkQuery(string $q)
execQuery(ilDBInterface $db, string $str)
array $custom_updates_content
setCustomUpdatesCurrentVersion(?int $a_version)
Iterator $ctrl_structure_iterator
bool $custom_updates_info_read
applyUpdateNr(int $nr, bool $custom_update=false)
Apply a custom database update or a plugin update.
INIFile Parser Early access in init proceess! Avoid further dependencies like logging or other servic...
ILIAS Setting Class.
Interface ilDBInterface.
query(string $query)
Run a (read-only) Query on the database.
global $DIC
Definition: shib_login.php:26
$q
Definition: shib_logout.php:23
$GLOBALS["DIC"]
Definition: wac.php:54