1 <?php |
|
2 |
|
3 namespace bfw { |
|
4 |
|
5 /** |
|
6 * Copyright(C) 2015 Markus Bröker<broeker.markus@googlemail.com> |
|
7 * |
|
8 */ |
|
9 class Database implements DBInterface { |
|
10 private static $logger = null; |
|
11 |
|
12 private $link; |
|
13 private static $handle = null; |
|
14 |
|
15 private function __construct() { |
|
16 self::$logger = \Logger::getLogger('__CLASS__'); |
|
17 |
|
18 $this->link = mysqli_connect($host = 'localhost', $user = 'ticketsystem', $password = 'ticketsystem', $database = 'ticketsystem'); |
|
19 mysqli_set_charset($this->link, 'utf8'); |
|
20 } |
|
21 |
|
22 /** |
|
23 * <b>Liefert das Singleton-Pattern der Datenbank-Schicht</b> |
|
24 * |
|
25 * Es existiert in einem Lauf, einem Scope, immer nur ein DB-Handle zur gleichen Zeit. |
|
26 * |
|
27 * Damit das ganze vernünftig flutscht, muss man natürlich berücksichtigen, dass ein SP state-lastig ist! |
|
28 * |
|
29 * Definition des States: Ein Abfrageergebnis stellt solange den State des SP da, bis eine neue Abfrage |
|
30 * einen neuen State erzeugt. |
|
31 * |
|
32 * @return Database|null |
|
33 */ |
|
34 public static function getInstance() { |
|
35 if (self::$handle == null) { |
|
36 self::$handle = new Database(); |
|
37 } |
|
38 |
|
39 return self::$handle; |
|
40 } |
|
41 |
|
42 /** |
|
43 * <b>Std-Abfrage Methode der DB-Klasse</b> |
|
44 * |
|
45 * Das übergebene SQL-Statement wird als assoziatives, ein-oder mehrdimensionales Array zurück geliefert. |
|
46 * |
|
47 * array = ( |
|
48 * 'id' => 1, |
|
49 * 'name' => 'Ticket', |
|
50 * ); |
|
51 * |
|
52 * @param $sql |
|
53 * @return array|null |
|
54 */ |
|
55 public function query($sql) { |
|
56 self::$logger->info(sprintf('%s(%s) ', __METHOD__, $sql)); |
|
57 |
|
58 $result = mysqli_query($this->link, $sql); |
|
59 |
|
60 if ($result == false) { |
|
61 return null; |
|
62 } |
|
63 |
|
64 if ($result->num_rows == 0) { |
|
65 return null; |
|
66 } |
|
67 |
|
68 $rows = array(); |
|
69 while (($row = $result->fetch_assoc())) { |
|
70 $rows[] = $row; |
|
71 } |
|
72 |
|
73 |
|
74 return $rows; |
|
75 } |
|
76 |
|
77 /** |
|
78 * <b>Abfragen, die kein ResultSet zurück liefern</b> |
|
79 * |
|
80 * SQL-Statements, die nur TRUE oder FALSE zurück liefern, |
|
81 * müssen per EXECUTE ausgeführt werden. |
|
82 * |
|
83 * @param $sql |
|
84 * @return bool|mysqli_result |
|
85 */ |
|
86 public function execute($sql) { |
|
87 self::$logger->info(sprintf('%s(%s) ', __METHOD__, $sql)); |
|
88 |
|
89 $result = mysqli_query($this->link, $sql); |
|
90 |
|
91 return $result; |
|
92 } |
|
93 |
|
94 /** |
|
95 * <b>Die einfache Fetch-Methode für das Table-Row-Pattern</b> |
|
96 * |
|
97 * Es wird ein SQL Statement bezogen auf die aktuelle Tabelle zusammen |
|
98 * gebaut. Dieses kann optional eine WHERE clause beinhalten. |
|
99 * |
|
100 * @param $table |
|
101 * @param string $cond |
|
102 * @return array|null |
|
103 */ |
|
104 public function fetch($table, $cond = 'id > 1') { |
|
105 self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $cond)); |
|
106 |
|
107 $sql = " |
|
108 SELECT |
|
109 * |
|
110 FROM |
|
111 $table |
|
112 WHERE |
|
113 $cond |
|
114 "; |
|
115 |
|
116 $result = mysqli_query($this->link, $sql); |
|
117 |
|
118 if ($result == false) { |
|
119 return null; |
|
120 } |
|
121 |
|
122 return $result->fetch_assoc(); |
|
123 } |
|
124 |
|
125 /** |
|
126 * <b>Die multiple Fetch-Methode für das Table-Row-Pattern</b> |
|
127 * |
|
128 * Der Rückgabewert ist ein Array mit allen Zeilen als assoziatives Array |
|
129 * |
|
130 * @param $table |
|
131 * @param string $cond |
|
132 * @return array|null |
|
133 */ |
|
134 public function fetchAll($table, $cond = 'id > 0') { |
|
135 self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $cond)); |
|
136 |
|
137 $sql = sprintf(" |
|
138 SELECT |
|
139 * |
|
140 FROM |
|
141 `%s` |
|
142 WHERE |
|
143 %s |
|
144 ", $table, $cond); |
|
145 |
|
146 return $this->query($sql); |
|
147 } |
|
148 |
|
149 /** |
|
150 * <b>Die einfache Find-Methode für das Table-Row-Pattern</b> |
|
151 * |
|
152 * Der Rückgabewert ist entweder die Tabellenzeile 'id' oder null |
|
153 * im assoziativen Array. |
|
154 * |
|
155 * @param $table |
|
156 * @param $id |
|
157 * @return array|null |
|
158 */ |
|
159 public function find($table, $id) { |
|
160 self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $id)); |
|
161 |
|
162 $sql = sprintf(" |
|
163 SELECT |
|
164 * |
|
165 FROM |
|
166 `%s` |
|
167 WHERE |
|
168 `id` = %d |
|
169 ", $table, $id); |
|
170 |
|
171 $result = mysqli_query($this->link, $sql); |
|
172 |
|
173 if ($result == false) { |
|
174 return null; |
|
175 } |
|
176 |
|
177 return $result->fetch_assoc(); |
|
178 } |
|
179 |
|
180 /** |
|
181 * <b>Die multiple Find-Methode für das Table-Row-Pattern</b> |
|
182 * |
|
183 * Es liefert alle Reihen als assoziatives Array zurück. |
|
184 * |
|
185 * @param $table |
|
186 * @return array|null |
|
187 */ |
|
188 public function findAll($table, $sys_id = 1) { |
|
189 self::$logger->info(sprintf('%s(%s) ', __METHOD__, $table)); |
|
190 |
|
191 $sql = sprintf(" |
|
192 SELECT |
|
193 * |
|
194 FROM |
|
195 `%s` |
|
196 WHERE |
|
197 `id` > %d |
|
198 ", $table, $sys_id); |
|
199 |
|
200 return $this->query($sql); |
|
201 } |
|
202 |
|
203 /** |
|
204 * <b>Liefert ein Resultset bezogen auf ein bestimmtes Feld zurück</b> |
|
205 * |
|
206 * @param $table |
|
207 * @param $field |
|
208 * @param $value |
|
209 * @return array|null |
|
210 */ |
|
211 public function findByField($table, $field, $value) { |
|
212 self::$logger->info(sprintf('%s(%s, %s, %s) ', __METHOD__, $table, $field, $value)); |
|
213 |
|
214 $sql = sprintf(" |
|
215 SELECT |
|
216 * |
|
217 FROM |
|
218 `%s` |
|
219 WHERE |
|
220 `%s` = '%s' |
|
221 ", $table, $field, $value); |
|
222 |
|
223 $result = mysqli_query($this->link, $sql); |
|
224 |
|
225 if ($result == false) { |
|
226 return null; |
|
227 } |
|
228 |
|
229 return $result->fetch_assoc(); |
|
230 } |
|
231 |
|
232 /** |
|
233 * <b>Liefert mehrere Resultsets bezogen auf ein bestimmtes Feld zurück</b> |
|
234 * |
|
235 * @param $table |
|
236 * @param $field |
|
237 * @param $value |
|
238 * @return array|null |
|
239 */ |
|
240 public function findAllByField($table, $field, $value) { |
|
241 self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $field)); |
|
242 |
|
243 $sql = sprintf(" |
|
244 SELECT |
|
245 * |
|
246 FROM |
|
247 `%s` |
|
248 WHERE |
|
249 `%s` = '%s' |
|
250 ", $table, $field, $value); |
|
251 |
|
252 return $this->query($sql); |
|
253 } |
|
254 |
|
255 /** |
|
256 * <b>Die Standard Persist Methode erstellt einen neuen DB-Eintrag in der angegebenen Tabelle</b> |
|
257 * |
|
258 * @param $table |
|
259 * @param $array |
|
260 * @return bool|mysqli_result |
|
261 */ |
|
262 public function persist($table, $array) { |
|
263 self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, print_r($array, true))); |
|
264 |
|
265 $keys = array(); |
|
266 foreach (array_keys($array) as $key) { |
|
267 if ($key != 'id') { |
|
268 $keys[] = sprintf("`%s`", $key); |
|
269 } |
|
270 } |
|
271 |
|
272 $fieldList = implode(", ", $keys); |
|
273 |
|
274 $values = array(); |
|
275 foreach ($array as $key => $value) { |
|
276 if ($key != 'id') { |
|
277 $values[] = sprintf("'%s'", $value); |
|
278 } |
|
279 } |
|
280 |
|
281 $fields = implode(",", $values); |
|
282 |
|
283 $sql = sprintf(" |
|
284 INSERT INTO `%s` |
|
285 (`id`, %s) VALUES (NULL, %s) |
|
286 ", $table, $fieldList, $fields); |
|
287 |
|
288 return $this->execute($sql); |
|
289 } |
|
290 |
|
291 /** |
|
292 * <b>Die Standard store Methode aktualisiert einen DB-Eintrag in der angegebenen Tabelle</b> |
|
293 * |
|
294 * @param $table |
|
295 * @param $id |
|
296 * @param $array |
|
297 * @return bool |
|
298 */ |
|
299 public function store($table, $id, $array) { |
|
300 self::$logger->info(sprintf('%s(%s, %d, %s) ', __METHOD__, $table, $id, print_r($array, true))); |
|
301 |
|
302 $list = array(); |
|
303 foreach ($array as $key => $value) { |
|
304 if ($key != 'id') { |
|
305 $list[] = sprintf("`%s` = '%s'", $key, $value); |
|
306 } |
|
307 } |
|
308 |
|
309 $listItems = implode(", ", $list); |
|
310 |
|
311 $sql = sprintf(" |
|
312 UPDATE `%s` |
|
313 SET %s |
|
314 WHERE `id` = %d |
|
315 ", $table, $listItems, $id); |
|
316 |
|
317 |
|
318 return $this->execute($sql); |
|
319 } |
|
320 |
|
321 /** |
|
322 * <b>Die Standard Delete Methode löscht einen bestehenden DB-Eintrag aus der angegebenen Tabelle</b> |
|
323 * |
|
324 * @param $table |
|
325 * @param $id |
|
326 * @return bool |
|
327 */ |
|
328 public function delete($table, $id) { |
|
329 self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $id)); |
|
330 |
|
331 $sql = sprintf(" |
|
332 DELETE FROM `%s` |
|
333 WHERE `id` = %d; |
|
334 ", $table, $id); |
|
335 |
|
336 return $this->execute($sql); |
|
337 } |
|
338 |
|
339 /** |
|
340 * <b>Liefert die letzte, verwendete ID, die eingefügt wurde.</b> |
|
341 * |
|
342 * Es gilt zu beachten, dass es sich hierbei um eine state-behaftete Methode handelt. |
|
343 * |
|
344 * <b>Nach 3 Inserts liefert diese Methode definitiv nur den PK des letzten INSERTS.</b> |
|
345 * |
|
346 * @return int|string |
|
347 */ |
|
348 public function getLastInsertedId() { |
|
349 $lastInsertedId = mysqli_insert_id($this->link); |
|
350 |
|
351 self::$logger->info(sprintf('%s(): %d', __METHOD__, $lastInsertedId)); |
|
352 |
|
353 return $lastInsertedId; |
|
354 } |
|
355 |
|
356 /** |
|
357 * <b>Diese Methode löscht alle Tickets, History und Benutzer weg</b> |
|
358 * |
|
359 * Diese Methode sollte dann aufgerufen werden, wenn die Anwendung deployed wird |
|
360 * |
|
361 * Auf Deutsch: "Vor der Präsi alles weglöschen." |
|
362 * |
|
363 * @return bool |
|
364 */ |
|
365 public function cleanup() { |
|
366 $status = $this->execute("DELETE FROM `t_ticket` WHERE `id` > 1;"); |
|
367 $status &= $this->execute("DELETE FROM `t_history` WHERE `id` > 1;"); |
|
368 $status &= $this->execute("DELETE FROM `t_user` WHERE `id` > 2;"); |
|
369 |
|
370 $status &= $this->execute("ALTER TABLE `t_history` AUTO_INCREMENT = 1;"); |
|
371 $status &= $this->execute("ALTER TABLE `t_ticket` AUTO_INCREMENT = 1;"); |
|
372 $status &= $this->execute("ALTER TABLE `t_user` AUTO_INCREMENT = 2;"); |
|
373 |
|
374 return $status; |
|
375 } |
|
376 |
|
377 /** |
|
378 * <b>Import von Datensätzen im CSV-Format(besser gesagt SSV-Format)</b> |
|
379 * |
|
380 * Die Tabelle 'table' wird automatisiert mit den Werten aus der SSV-Datei befüllt. |
|
381 * |
|
382 * @param $table |
|
383 * @param $filename |
|
384 * @return bool |
|
385 */ |
|
386 public function csvImport($table, $filename) { |
|
387 $db = Database::getInstance(); |
|
388 |
|
389 $handle = fopen($filename, 'r'); |
|
390 |
|
391 $lines = array(); |
|
392 while (!feof($handle)) { |
|
393 $lines[] = trim(fgets($handle), "[\r\n\t]"); |
|
394 } |
|
395 |
|
396 fclose($handle); |
|
397 |
|
398 if (count($lines) < 2) { |
|
399 return false; |
|
400 } |
|
401 |
|
402 $spaltenKoepfeArray = explode(';', $lines[0]); |
|
403 for ($i = 0; $i < count($spaltenKoepfeArray); $i++) { |
|
404 $spaltenKoepfeArray[$i] = sprintf("`%s`", $spaltenKoepfeArray[$i]); |
|
405 } |
|
406 |
|
407 $spaltenInhaltArray = array(); |
|
408 for ($i = 1; $i < count($lines); $i++) { |
|
409 $spaltenInhaltArray[] = explode(';', $lines[$i]); |
|
410 } |
|
411 |
|
412 $spaltenKoepfe = implode(', ', $spaltenKoepfeArray); |
|
413 |
|
414 foreach ($spaltenInhaltArray as $sia) { |
|
415 for ($i = 0; $i < count($sia); $i++) { |
|
416 |
|
417 if ($spaltenKoepfeArray[$i] == '`last_access`') { |
|
418 $sia[$i] = sprintf("'%s'", date("Y-m-d H:i:s")); |
|
419 } else { |
|
420 $sia[$i] = sprintf("'%s'", $sia[$i]); |
|
421 } |
|
422 } |
|
423 |
|
424 $spaltenInhalt = implode(', ', $sia); |
|
425 if (count($spaltenKoepfeArray) == count($sia)) { |
|
426 $sql = sprintf("INSERT INTO %s(id, %s) VALUES(NULL, %s);", $table, $spaltenKoepfe, $spaltenInhalt); |
|
427 if (!$db->execute($sql)) { |
|
428 |
|
429 return false; |
|
430 } |
|
431 } |
|
432 } |
|
433 |
|
434 return true; |
|
435 } |
|
436 |
|
437 } |
|
438 } |
|