diff --git a/classes/bfw/Database.php b/classes/bfw/Database.php new file mode 100644 --- /dev/null +++ b/classes/bfw/Database.php @@ -0,0 +1,438 @@ + + * + */ + class Database implements DBInterface { + private static $logger = null; + + private $link; + private static $handle = null; + + private function __construct() { + self::$logger = \Logger::getLogger('__CLASS__'); + + $this->link = mysqli_connect($host = 'localhost', $user = 'ticketsystem', $password = 'ticketsystem', $database = 'ticketsystem'); + mysqli_set_charset($this->link, 'utf8'); + } + + /** + * Liefert das Singleton-Pattern der Datenbank-Schicht + * + * Es existiert in einem Lauf, einem Scope, immer nur ein DB-Handle zur gleichen Zeit. + * + * Damit das ganze vernünftig flutscht, muss man natürlich berücksichtigen, dass ein SP state-lastig ist! + * + * Definition des States: Ein Abfrageergebnis stellt solange den State des SP da, bis eine neue Abfrage + * einen neuen State erzeugt. + * + * @return Database|null + */ + public static function getInstance() { + if (self::$handle == null) { + self::$handle = new Database(); + } + + return self::$handle; + } + + /** + * Std-Abfrage Methode der DB-Klasse + * + * Das übergebene SQL-Statement wird als assoziatives, ein-oder mehrdimensionales Array zurück geliefert. + * + * array = ( + * 'id' => 1, + * 'name' => 'Ticket', + * ); + * + * @param $sql + * @return array|null + */ + public function query($sql) { + self::$logger->info(sprintf('%s(%s) ', __METHOD__, $sql)); + + $result = mysqli_query($this->link, $sql); + + if ($result == false) { + return null; + } + + if ($result->num_rows == 0) { + return null; + } + + $rows = array(); + while (($row = $result->fetch_assoc())) { + $rows[] = $row; + } + + + return $rows; + } + + /** + * Abfragen, die kein ResultSet zurück liefern + * + * SQL-Statements, die nur TRUE oder FALSE zurück liefern, + * müssen per EXECUTE ausgeführt werden. + * + * @param $sql + * @return bool|mysqli_result + */ + public function execute($sql) { + self::$logger->info(sprintf('%s(%s) ', __METHOD__, $sql)); + + $result = mysqli_query($this->link, $sql); + + return $result; + } + + /** + * Die einfache Fetch-Methode für das Table-Row-Pattern + * + * Es wird ein SQL Statement bezogen auf die aktuelle Tabelle zusammen + * gebaut. Dieses kann optional eine WHERE clause beinhalten. + * + * @param $table + * @param string $cond + * @return array|null + */ + public function fetch($table, $cond = 'id > 1') { + self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $cond)); + + $sql = " + SELECT + * + FROM + $table + WHERE + $cond + "; + + $result = mysqli_query($this->link, $sql); + + if ($result == false) { + return null; + } + + return $result->fetch_assoc(); + } + + /** + * Die multiple Fetch-Methode für das Table-Row-Pattern + * + * Der Rückgabewert ist ein Array mit allen Zeilen als assoziatives Array + * + * @param $table + * @param string $cond + * @return array|null + */ + public function fetchAll($table, $cond = 'id > 0') { + self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $cond)); + + $sql = sprintf(" + SELECT + * + FROM + `%s` + WHERE + %s + ", $table, $cond); + + return $this->query($sql); + } + + /** + * Die einfache Find-Methode für das Table-Row-Pattern + * + * Der Rückgabewert ist entweder die Tabellenzeile 'id' oder null + * im assoziativen Array. + * + * @param $table + * @param $id + * @return array|null + */ + public function find($table, $id) { + self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $id)); + + $sql = sprintf(" + SELECT + * + FROM + `%s` + WHERE + `id` = %d + ", $table, $id); + + $result = mysqli_query($this->link, $sql); + + if ($result == false) { + return null; + } + + return $result->fetch_assoc(); + } + + /** + * Die multiple Find-Methode für das Table-Row-Pattern + * + * Es liefert alle Reihen als assoziatives Array zurück. + * + * @param $table + * @return array|null + */ + public function findAll($table, $sys_id = 1) { + self::$logger->info(sprintf('%s(%s) ', __METHOD__, $table)); + + $sql = sprintf(" + SELECT + * + FROM + `%s` + WHERE + `id` > %d + ", $table, $sys_id); + + return $this->query($sql); + } + + /** + * Liefert ein Resultset bezogen auf ein bestimmtes Feld zurück + * + * @param $table + * @param $field + * @param $value + * @return array|null + */ + public function findByField($table, $field, $value) { + self::$logger->info(sprintf('%s(%s, %s, %s) ', __METHOD__, $table, $field, $value)); + + $sql = sprintf(" + SELECT + * + FROM + `%s` + WHERE + `%s` = '%s' + ", $table, $field, $value); + + $result = mysqli_query($this->link, $sql); + + if ($result == false) { + return null; + } + + return $result->fetch_assoc(); + } + + /** + * Liefert mehrere Resultsets bezogen auf ein bestimmtes Feld zurück + * + * @param $table + * @param $field + * @param $value + * @return array|null + */ + public function findAllByField($table, $field, $value) { + self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $field)); + + $sql = sprintf(" + SELECT + * + FROM + `%s` + WHERE + `%s` = '%s' + ", $table, $field, $value); + + return $this->query($sql); + } + + /** + * Die Standard Persist Methode erstellt einen neuen DB-Eintrag in der angegebenen Tabelle + * + * @param $table + * @param $array + * @return bool|mysqli_result + */ + public function persist($table, $array) { + self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, print_r($array, true))); + + $keys = array(); + foreach (array_keys($array) as $key) { + if ($key != 'id') { + $keys[] = sprintf("`%s`", $key); + } + } + + $fieldList = implode(", ", $keys); + + $values = array(); + foreach ($array as $key => $value) { + if ($key != 'id') { + $values[] = sprintf("'%s'", $value); + } + } + + $fields = implode(",", $values); + + $sql = sprintf(" + INSERT INTO `%s` + (`id`, %s) VALUES (NULL, %s) + ", $table, $fieldList, $fields); + + return $this->execute($sql); + } + + /** + * Die Standard store Methode aktualisiert einen DB-Eintrag in der angegebenen Tabelle + * + * @param $table + * @param $id + * @param $array + * @return bool + */ + public function store($table, $id, $array) { + self::$logger->info(sprintf('%s(%s, %d, %s) ', __METHOD__, $table, $id, print_r($array, true))); + + $list = array(); + foreach ($array as $key => $value) { + if ($key != 'id') { + $list[] = sprintf("`%s` = '%s'", $key, $value); + } + } + + $listItems = implode(", ", $list); + + $sql = sprintf(" + UPDATE `%s` + SET %s + WHERE `id` = %d + ", $table, $listItems, $id); + + + return $this->execute($sql); + } + + /** + * Die Standard Delete Methode löscht einen bestehenden DB-Eintrag aus der angegebenen Tabelle + * + * @param $table + * @param $id + * @return bool + */ + public function delete($table, $id) { + self::$logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $id)); + + $sql = sprintf(" + DELETE FROM `%s` + WHERE `id` = %d; + ", $table, $id); + + return $this->execute($sql); + } + + /** + * Liefert die letzte, verwendete ID, die eingefügt wurde. + * + * Es gilt zu beachten, dass es sich hierbei um eine state-behaftete Methode handelt. + * + * Nach 3 Inserts liefert diese Methode definitiv nur den PK des letzten INSERTS. + * + * @return int|string + */ + public function getLastInsertedId() { + $lastInsertedId = mysqli_insert_id($this->link); + + self::$logger->info(sprintf('%s(): %d', __METHOD__, $lastInsertedId)); + + return $lastInsertedId; + } + + /** + * Diese Methode löscht alle Tickets, History und Benutzer weg + * + * Diese Methode sollte dann aufgerufen werden, wenn die Anwendung deployed wird + * + * Auf Deutsch: "Vor der Präsi alles weglöschen." + * + * @return bool + */ + public function cleanup() { + $status = $this->execute("DELETE FROM `t_ticket` WHERE `id` > 1;"); + $status &= $this->execute("DELETE FROM `t_history` WHERE `id` > 1;"); + $status &= $this->execute("DELETE FROM `t_user` WHERE `id` > 2;"); + + $status &= $this->execute("ALTER TABLE `t_history` AUTO_INCREMENT = 1;"); + $status &= $this->execute("ALTER TABLE `t_ticket` AUTO_INCREMENT = 1;"); + $status &= $this->execute("ALTER TABLE `t_user` AUTO_INCREMENT = 2;"); + + return $status; + } + + /** + * Import von Datensätzen im CSV-Format(besser gesagt SSV-Format) + * + * Die Tabelle 'table' wird automatisiert mit den Werten aus der SSV-Datei befüllt. + * + * @param $table + * @param $filename + * @return bool + */ + public function csvImport($table, $filename) { + $db = Database::getInstance(); + + $handle = fopen($filename, 'r'); + + $lines = array(); + while (!feof($handle)) { + $lines[] = trim(fgets($handle), "[\r\n\t]"); + } + + fclose($handle); + + if (count($lines) < 2) { + return false; + } + + $spaltenKoepfeArray = explode(';', $lines[0]); + for ($i = 0; $i < count($spaltenKoepfeArray); $i++) { + $spaltenKoepfeArray[$i] = sprintf("`%s`", $spaltenKoepfeArray[$i]); + } + + $spaltenInhaltArray = array(); + for ($i = 1; $i < count($lines); $i++) { + $spaltenInhaltArray[] = explode(';', $lines[$i]); + } + + $spaltenKoepfe = implode(', ', $spaltenKoepfeArray); + + foreach ($spaltenInhaltArray as $sia) { + for ($i = 0; $i < count($sia); $i++) { + + if ($spaltenKoepfeArray[$i] == '`last_access`') { + $sia[$i] = sprintf("'%s'", date("Y-m-d H:i:s")); + } else { + $sia[$i] = sprintf("'%s'", $sia[$i]); + } + } + + $spaltenInhalt = implode(', ', $sia); + if (count($spaltenKoepfeArray) == count($sia)) { + $sql = sprintf("INSERT INTO %s(id, %s) VALUES(NULL, %s);", $table, $spaltenKoepfe, $spaltenInhalt); + if (!$db->execute($sql)) { + + return false; + } + } + } + + return true; + } + + } +} \ No newline at end of file