SQL-Quoting hinzu gefügt
authorMarkus Broeker<broeker.markus@googlemail.com>
Sun, 14 Feb 2016 14:58:14 +0100
changeset 36 011596fe2830
parent 35 e21fb19dc319
child 37 f4fce35327ff
SQL-Quoting hinzu gefügt
classes/bfw/core/Entity.php
classes/bfw/database/Database.php
--- a/classes/bfw/core/Entity.php
+++ b/classes/bfw/core/Entity.php
@@ -1,270 +1,278 @@
-<?php
-
-/**
- * Copyright(C) 2015 Markus Bröker<broeker.markus@googlemail.com>
- *
- */
-
-namespace bfw\core;
-
-use bfw\database\Database;
-use Logger;
-
-/**
- * Class Entity
- *
- * Entity besitzt einen State in $data
- *
- *
- * @method string getId()
- * @method setId($param)
- */
-class Entity {
-
-    protected $logger;
-    protected $db;
-    protected $table;
-    protected $data;
-
-    /**
-     * @param $table
-     */
-    public function __construct($table) {
-        $this->logger = Logger::getLogger(get_class($this));
-
-        $this->db = Database::getInstance();
-
-        $this->table = $table;
-        $this->data = array();
-    }
-
-    /**
-     * Magische Methode: Was soll beim Eintüten eingetütet werden?
-     *
-     * @return array
-     */
-    public function __sleep() {
-        return array(
-            'table',
-            'data',
-        );
-    }
-
-    /**
-     * Magische Methode: Was soll nach dem Auspacken noch passieren?
-     */
-    public function __wakeup() {
-        $this->logger = Logger::getLogger(get_class($this));
-        $this->db = Database::getInstance();
-    }
-
-    /**
-     * <b>Herzstück des Persistence-Frameworks</b>
-     *
-     * Dynamische Erzeugung von Getttern- und Settern
-     *
-     * Anstatt diese explizit zu pflegen und zu warten,
-     * werden Diese dynamisch, on, the fly, erzeugt.
-     *
-     * <b>Der Vorteil: Nicht Konfigurieren, nicht Erzeugen. Einfach Nutzen...</b>
-     *
-     * @param $methodName
-     * @param null $params
-     * @return mixed
-     */
-    public function __call($methodName, $params = null) {
-        $prefix = substr($methodName, 0, 3);
-        
-        $key = lcfirst(substr($methodName, 3));
-        $key = strtolower(preg_replace('/([A-Z])/', "_$1", $key));
-
-        if ($prefix == 'set') {
-            $value = $params[0];
-
-            // no data, no state, null
-            if (!is_array($this->data)) {
-                return null;
-            }
-
-            $this->data[$key] = $value;
-
-            // fluent please!
-            return $this;
-        } else if ($prefix == 'get') {
-
-            // no data, no state, null
-            if (!is_array($this->data)) {
-                return null;
-            }
-
-            if (array_key_exists($key, $this->data)) {
-                return $this->data[$key];
-            }
-        }
-
-        exit(sprintf('Unbekannte Methode %s::%s(%s, %s) wurde aufgerufen.', get_class($this), $methodName, $key, $prefix));
-    }
-
-    /**
-     * <b>Vereinfachte Find Methode bezogen auf die jeweilige Instanz</b>
-     *
-     * @param $id
-     * @return Model
-     */
-    public function find($id) {
-        $this->logger->info(sprintf('%s(%d) ', __METHOD__, $id));
-
-        if (($this->data = $this->db->find($this->table, $id)) == null) {
-            return null;
-        }
-
-        return $this;
-    }
-
-    /**
-     * <b>Die Findall Methode erzeugt typsicher den Supertyp</b>
-     *
-     * @param int $initial_id
-     * @return Entity[]
-     */
-    public function findAll($initial_id = 1) {
-        $this->logger->info(sprintf('%s(%d) ', __METHOD__, $initial_id));
-
-        $rows = $this->db->findAll($this->table, $initial_id);
-
-        if (count($rows) == 0) {
-            return array();
-        }
-
-        $list = array();
-        foreach ($rows as $row) {
-            $item = new static();
-            $item->data = $row;
-
-            $list[] = $item;
-        }
-
-        $this->logger->info(sprintf('%s(): %d', __METHOD__, count($list)));
-
-        return $list;
-    }
-
-    /**
-     * <b>Vereinfachte FindByField Methode</b>
-     *
-     * @param $field
-     * @param $value
-     *
-     * @return Entity
-     */
-    public function findByField($field, $value) {
-        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $field, $value));
-
-        $this->data = $this->db->findByField($this->table, $field, $value);
-
-        // Keine Daten, keine Instanz
-        if ($this->data == null) {
-            return null;
-        }
-
-        return $this;
-    }
-
-    /**
-     * <b>Vereinfachte FindAllByField Methode</b>
-     *
-     * Erzeugt on the fly ein array mit dem Supertyp der Klasseninstanz
-     * @param $field
-     * @param $value
-     *
-     * @return Entity[]
-     */
-    public function findAllByField($field, $value) {
-        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $field, $value));
-
-        $rows = $this->db->findAllByField($this->table, $field, $value);
-
-        if ($rows == null) {
-            return null;
-        }
-
-        $list = array();
-        foreach ($rows as $row) {
-            $item = new static();
-            $item->data = $row;
-
-            $list[] = $item;
-        }
-
-        return $list;
-    }
-
-    /**
-     * <b>Vereinfachte persist Methode</b>
-     *
-     * Der Logger loggt nur die Nutzdaten, deswegen sieht das im Log identisch aus.
-     *
-     * Es handelt sich allerdings einmal um ein Objekt und einmal nur um ein Array.
-     *
-     * @return bool
-     */
-    public function persist() {
-        $this->logger->info(sprintf('%s(%s)', __METHOD__, print_r($this->getData(), true)));
-
-        return $this->db->persist($this->table, $this->getData());
-    }
-
-    public function getData() {
-        return $this->data;
-    }
-
-    /**
-     * <b>Vereinfachte store Methode</b>
-     *
-     * @return bool
-     */
-    public function store() {
-        $this->logger->info(sprintf('%s(%d, %s)', __METHOD__, $this->getId(), print_r($this->getData(), true)));
-
-        if ($this->getId() > 1) {
-            return $this->db->store($this->table, $this->getId(), $this->getData());
-        }
-
-        return false;
-    }
-
-    /**
-     * <b>Vereinfachte delete Methode</b>
-     *
-     * @return bool
-     */
-    public function delete() {
-        $this->logger->info(sprintf('%s(%d) ', __METHOD__, $this->getId()));
-
-        if ($this->getId() > 1) {
-            return $this->db->delete($this->table, $this->getId());
-        }
-
-        return false;
-    }
-
-    /**
-     * Experimental Feature
-     *
-     * @param $array
-     * @return $this
-     */
-    public function merge($array) {
-        $this->data = array_merge($this->data, $array);
-
-        return $this;
-    }
-
-    /**
-     * @return string
-     */
-    public function getLastError() {
-        return $this->db->getLastError();
-    }
-
-}
+<?php
+
+/**
+ * Copyright(C) 2015 Markus Bröker<broeker.markus@googlemail.com>
+ *
+ */
+
+namespace bfw\core;
+
+use bfw\database\Database;
+use Logger;
+
+/**
+ * Class Entity
+ *
+ * Entity besitzt einen State in $data
+ *
+ *
+ * @method string getId()
+ * @method setId($param)
+ */
+class Entity {
+
+    protected $logger;
+    protected $db;
+    protected $table;
+    protected $data;
+
+    /**
+     * @param $table
+     */
+    public function __construct($table) {
+        $this->logger = Logger::getLogger(get_class($this));
+
+        $this->db = Database::getInstance();
+
+        $this->table = $table;
+        $this->data = array();
+    }
+
+    /**
+     * Magische Methode: Was soll beim Eintüten eingetütet werden?
+     *
+     * @return array
+     */
+    public function __sleep() {
+        return array(
+            'table',
+            'data',
+        );
+    }
+
+    /**
+     * Magische Methode: Was soll nach dem Auspacken noch passieren?
+     */
+    public function __wakeup() {
+        $this->logger = Logger::getLogger(get_class($this));
+        $this->db = Database::getInstance();
+    }
+
+    /**
+     * <b>Herzstück des Persistence-Frameworks</b>
+     *
+     * Dynamische Erzeugung von Getttern- und Settern
+     *
+     * Anstatt diese explizit zu pflegen und zu warten,
+     * werden Diese dynamisch, on, the fly, erzeugt.
+     *
+     * <b>Der Vorteil: Nicht Konfigurieren, nicht Erzeugen. Einfach Nutzen...</b>
+     *
+     * @param $methodName
+     * @param null $params
+     * @return mixed
+     */
+    public function __call($methodName, $params = null) {
+        $prefix = substr($methodName, 0, 3);
+
+        $key = lcfirst(substr($methodName, 3));
+        $key = strtolower(preg_replace('/([A-Z])/', "_$1", $key));
+
+        if ($prefix == 'set') {
+            $value = $params[0];
+
+            // no data, no state, null
+            if (!is_array($this->data)) {
+                return null;
+            }
+
+            $this->data[$key] = $value;
+
+            // fluent please!
+            return $this;
+        } else if ($prefix == 'get') {
+
+            // no data, no state, null
+            if (!is_array($this->data)) {
+                return null;
+            }
+
+            if (array_key_exists($key, $this->data)) {
+                return $this->data[$key];
+            }
+        }
+
+        exit(sprintf('Unbekannte Methode %s::%s(%s, %s) wurde aufgerufen.', get_class($this), $methodName, $key, $prefix));
+    }
+
+    /**
+     * <b>Vereinfachte Find Methode bezogen auf die jeweilige Instanz</b>
+     *
+     * @param $id
+     * @return Model
+     */
+    public function find($id) {
+        $this->logger->info(sprintf('%s(%d) ', __METHOD__, $id));
+
+        if (($this->data = $this->db->find($this->table, $id)) == null) {
+            return null;
+        }
+
+        return $this;
+    }
+
+    /**
+     * <b>Die Findall Methode erzeugt typsicher den Supertyp</b>
+     *
+     * @param int $initial_id
+     * @return Entity[]
+     */
+    public function findAll($initial_id = 1) {
+        $this->logger->info(sprintf('%s(%d) ', __METHOD__, $initial_id));
+
+        $rows = $this->db->findAll($this->table, $initial_id);
+
+        if (count($rows) == 0) {
+            return array();
+        }
+
+        $list = array();
+        foreach ($rows as $row) {
+            $item = new static();
+            $item->data = $row;
+
+            $list[] = $item;
+        }
+
+        $this->logger->info(sprintf('%s(): %d', __METHOD__, count($list)));
+
+        return $list;
+    }
+
+    /**
+     * <b>Vereinfachte FindByField Methode</b>
+     *
+     * @param $field
+     * @param $value
+     *
+     * @return Entity
+     */
+    public function findByField($field, $value) {
+        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $field, $value));
+
+        $this->data = $this->db->findByField($this->table, $field, $value);
+
+        // Keine Daten, keine Instanz
+        if ($this->data == null) {
+            return null;
+        }
+
+        return $this;
+    }
+
+    /**
+     * <b>Vereinfachte FindAllByField Methode</b>
+     *
+     * Erzeugt on the fly ein array mit dem Supertyp der Klasseninstanz
+     * @param $field
+     * @param $value
+     *
+     * @return Entity[]
+     */
+    public function findAllByField($field, $value) {
+        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $field, $value));
+
+        $rows = $this->db->findAllByField($this->table, $field, $value);
+
+        if ($rows == null) {
+            return null;
+        }
+
+        $list = array();
+        foreach ($rows as $row) {
+            $item = new static();
+            $item->data = $row;
+
+            $list[] = $item;
+        }
+
+        return $list;
+    }
+
+    /**
+     * <b>Vereinfachte persist Methode</b>
+     *
+     * Der Logger loggt nur die Nutzdaten, deswegen sieht das im Log identisch aus.
+     *
+     * Es handelt sich allerdings einmal um ein Objekt und einmal nur um ein Array.
+     *
+     * @return bool
+     */
+    public function persist() {
+        $this->logger->info(sprintf('%s(%s)', __METHOD__, print_r($this->getData(), true)));
+
+        return $this->db->persist($this->table, $this->getData());
+    }
+
+    public function getData() {
+        return $this->data;
+    }
+
+    /**
+     * <b>Vereinfachte store Methode</b>
+     *
+     * @return bool
+     */
+    public function store() {
+        $this->logger->info(sprintf('%s(%d, %s)', __METHOD__, $this->getId(), print_r($this->getData(), true)));
+
+        if ($this->getId() > 1) {
+            return $this->db->store($this->table, $this->getId(), $this->getData());
+        }
+
+        return false;
+    }
+
+    /**
+     * <b>Vereinfachte delete Methode</b>
+     *
+     * @return bool
+     */
+    public function delete() {
+        $this->logger->info(sprintf('%s(%d) ', __METHOD__, $this->getId()));
+
+        if ($this->getId() > 1) {
+            return $this->db->delete($this->table, $this->getId());
+        }
+
+        return false;
+    }
+
+    /**
+     * Experimental Feature
+     *
+     * @param $array
+     * @return $this
+     */
+    public function merge($array) {
+        $this->data = array_merge($this->data, $array);
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getLastError() {
+        return $this->db->getLastError();
+    }
+
+    /**
+     *
+     * @param string $string
+     * @return string
+     */
+    public function quote($string) {
+        return $this->db->quote($string);
+    }
+}
--- a/classes/bfw/database/Database.php
+++ b/classes/bfw/database/Database.php
@@ -1,426 +1,435 @@
-<?php
-
-/**
- * Copyright(C) 2015 Markus Bröker<broeker.markus@googlemail.com>
- *
- */
-
-namespace bfw\database;
-
-use bfw\Configuration;
-use Logger;
-use PDO;
-use PDOException;
-
-/**
- * Class Database
- */
-class Database implements DBInterface {
-
-    private static $handle = null;
-    private $logger;
-
-    /**
-     * @var PDO
-     */
-    private $pdo;
-
-    /**
-     * Database constructor.
-     * @param null|array $cfg
-     */
-    private function __construct($cfg = null) {
-        $this->logger = Logger::getLogger(__CLASS__);
-
-        if ($cfg == null) {
-            $cfg = Configuration::getDataSourceProperties();
-        }
-
-        $dsn = $cfg['dsn'];
-        $config = $cfg['config'];
-        $username = $cfg['username'];
-        $password = $cfg['password'];
-
-        $this->pdo = new PDO($dsn, $username, $password, $config);
-    }
-
-    /**
-     * <b>Liefert das Singleton-Pattern der Datenbank-Schicht</b>
-     *
-     * 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.
-     *
-     * @param null|array $cfg
-     * @return Database
-     */
-    public static function getInstance($cfg = null) {
-        if (self::$handle == null) {
-            self::$handle = new Database($cfg);
-        }
-
-        return self::$handle;
-    }
-
-    /**
-     * <b>Diese Methode löscht alle Benutzer weg</b>
-     *
-     * Diese Methode sollte dann aufgerufen werden, wenn die Anwendung deployed wird
-     *
-     * @return bool
-     */
-    public function cleanup() {
-        try {
-            $this->pdo->exec("DELETE FROM t_user WHERE id > 2;");
-            $this->pdo->exec("DELETE FROM t_group WHERE id > 5;");
-
-            $this->pdo->exec("ALTER TABLE t_user AUTO_INCREMENT = 2;");
-            $this->pdo->exec("ALTER TABLE t_group AUTO_INCREMENT = 5;");
-        } catch (PDOException $pdoe) {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     *
-     * @param string $table
-     * @param array $fields
-     * @param string $filename
-     * @param string $seperator
-     *
-     * @throws InvalidArgumentException
-     */
-    public function csvExport($table, $fields, $filename, $seperator = ';') {
-        $handle = fopen($filename, "w+");
-
-        if ($handle == FALSE) {
-            throw new InvalidArgumentException("Datei nicht gefunden: " . $filename);
-        }
-
-        $rows = $this->fetchAll(sprintf("SELECT %s FROM %s ORDER BY id", implode(", ", $fields), $table));
-
-        fwrite($handle, sprintf("%s\n", implode($seperator, $fields)));
-        foreach ($rows as $row) {
-            fwrite($handle, sprintf("%s\n", implode($seperator, $row)));
-        }
-
-        fclose($handle);
-    }
-
-    /**
-     * @param $table
-     * @param $cond
-     * @return array|null
-     */
-    public function fetchAll($table, $cond = 'id > 0') {
-        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $cond));
-
-        $stmt = $this->pdo->prepare(sprintf('
-            SELECT
-                *
-            FROM
-              %s
-            WHERE
-              %s
-            ', $table, $cond
-        ));
-
-        if ($stmt->execute()) {
-            return $stmt->fetchAll(PDO::FETCH_ASSOC);
-        }
-
-        return null;
-    }
-
-    /**
-     * @param $table
-     * @param $cond
-     * @return array|null
-     */
-    public function fetch($table, $cond = 'id > 0') {
-        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $cond));
-
-        $stmt = $this->pdo->prepare(sprintf('
-            SELECT
-                *
-            FROM
-              %s
-            WHERE
-              %s
-            LIMIT 1
-            ', $table, $cond
-        ));
-
-        if ($stmt->execute()) {
-            return $stmt->fetch(PDO::FETCH_ASSOC);
-        }
-
-        return null;
-    }
-
-    /**
-     *
-     * @param string $table
-     * @param string $filename
-     * @param string $seperator
-     *
-     * @throws InvalidArgumentException
-     */
-    public function csvImport($table, $filename, $seperator = ';') {
-        $handle = fopen($filename, "r");
-
-        if ($handle == FALSE) {
-            throw new InvalidArgumentException("Datei nicht gefunden: " . $filename);
-        }
-
-        $firstLine = trim(fgets($handle, 1024));
-        $firstExplodedLine = explode($seperator, $firstLine);
-        $firstImplodedLine = implode(", ", $firstExplodedLine);
-
-        while (($line = fgets($handle, 1024)) != NULL) {
-            $explodedLine = explode($seperator, trim($line));
-            $row = array();
-            foreach ($explodedLine as $explodedField) {
-                $row[] = "'$explodedField'";
-            }
-
-            $implodedLine = implode(", ", $row);
-            $this->pdo->exec(sprintf("INSERT INTO %s(id, %s) VALUES(NULL, %s);\n", $table, $firstImplodedLine, $implodedLine));
-        }
-
-        fclose($handle);
-    }
-
-    /**
-     * @param $table
-     * @param $id
-     * @return mixed|null
-     */
-    public function find($table, $id) {
-        $this->logger->info(sprintf('%s(%s, %d) ', __METHOD__, $table, $id));
-
-        $stmt = $this->pdo->prepare(
-                sprintf('
-              SELECT
-                *
-              FROM
-                %s
-              WHERE
-                id = :id
-              LIMIT 1
-            ', $table
-        ));
-
-        $stmt->bindParam(':id', $id);
-
-        $status = $stmt->execute();
-        if ($status) {
-            return $stmt->fetch(PDO::FETCH_ASSOC);
-        }
-
-        return null;
-    }
-
-    /**
-     * @param $table
-     * @param int $initial_id
-     * @return array|null
-     */
-    public function findAll($table, $initial_id = 0) {
-        $this->logger->info(sprintf('%s(%s, %d) ', __METHOD__, $table, $initial_id));
-
-        $stmt = $this->pdo->prepare(
-                sprintf('
-              SELECT
-                *
-              FROM
-                %s
-              WHERE
-                id > :id
-              ORDER BY ID ASC
-            ', $table
-        ));
-
-        $stmt->bindParam(':id', $initial_id);
-
-        if ($stmt->execute()) {
-            return $stmt->fetchAll(PDO::FETCH_ASSOC);
-        }
-
-        return null;
-    }
-
-    /**
-     * @param $table
-     * @param $field
-     * @param $value
-     * @return mixed|null
-     */
-    public function findByField($table, $field, $value) {
-        $this->logger->info(sprintf('%s(%s, %s, %s) ', __METHOD__, $table, $field, $value));
-
-        $stmt = $this->pdo->prepare(
-                sprintf('
-              SELECT
-                *
-              FROM
-                %s
-              WHERE
-                %s = :value
-              LIMIT 1
-            ', $table, $field
-        ));
-
-        $stmt->bindParam(':value', $value);
-
-        if ($stmt->execute()) {
-            return $stmt->fetch(PDO::FETCH_ASSOC);
-        }
-
-        return null;
-    }
-
-    /**
-     * @param $table
-     * @param $field
-     * @param $value
-     * @return array|null
-     */
-    function findAllByField($table, $field, $value) {
-        $this->logger->info(sprintf('%s(%s, %s, %s) ', __METHOD__, $table, $field, $value));
-
-        $stmt = $this->pdo->prepare(
-                sprintf('
-              SELECT
-                *
-              FROM
-                %s
-              WHERE
-                %s = :value
-            ', $table, $field
-        ));
-
-        $stmt->bindParam(':value', $value);
-
-        if ($stmt->execute()) {
-            return $stmt->fetchAll(PDO::FETCH_ASSOC);
-        }
-
-        return null;
-    }
-
-    /**
-     * @param $sql
-     * @return array|null
-     */
-    public function query($sql) {
-        $this->logger->info(sprintf('%s(%s) ', __METHOD__, $sql));
-
-        $stmt = $this->pdo->query($sql);
-
-        if ($stmt) {
-            return $stmt->fetchAll(PDO::FETCH_ASSOC);
-        }
-
-        return null;
-    }
-
-    /**
-     * @param $sql
-     * @return bool
-     */
-    public function execute($sql) {
-        return ($this->pdo->exec($sql) !== FALSE);
-    }
-
-    /**
-     * @param $table
-     * @param $array
-     * @return bool
-     */
-    public function persist($table, $array) {
-        $this->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->pdo->exec($sql) !== FALSE);
-    }
-
-    /**
-     * @param $table
-     * @param $id
-     * @param $array
-     * @return bool
-     */
-    public function store($table, $id, $array) {
-        $this->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->pdo->exec($sql) !== FALSE);
-    }
-
-    /**
-     * @param $table
-     * @param $id
-     * @return int
-     */
-    public function delete($table, $id) {
-        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $id));
-
-        $sql = sprintf("
-            DELETE FROM %s
-            WHERE id = %d;
-        ", $table, $id);
-
-        return ($this->pdo->exec($sql) !== FALSE);
-    }
-
-    public function getLastInsertedId() {
-        return $this->pdo->lastInsertId();
-    }
-
-    public function getLastError() {
-        return $this->pdo->errorCode();
-    }
-
-}
+<?php
+
+/**
+ * Copyright(C) 2015 Markus Bröker<broeker.markus@googlemail.com>
+ *
+ */
+
+namespace bfw\database;
+
+use bfw\Configuration;
+use Logger;
+use PDO;
+use PDOException;
+
+/**
+ * Class Database
+ */
+class Database implements DBInterface {
+
+    private static $handle = null;
+    private $logger;
+
+    /**
+     * @var PDO
+     */
+    private $pdo;
+
+    /**
+     * Database constructor.
+     * @param null|array $cfg
+     */
+    private function __construct($cfg = null) {
+        $this->logger = Logger::getLogger(__CLASS__);
+
+        if ($cfg == null) {
+            $cfg = Configuration::getDataSourceProperties();
+        }
+
+        $dsn = $cfg['dsn'];
+        $config = $cfg['config'];
+        $username = $cfg['username'];
+        $password = $cfg['password'];
+
+        $this->pdo = new PDO($dsn, $username, $password, $config);
+    }
+
+    /**
+     * <b>Liefert das Singleton-Pattern der Datenbank-Schicht</b>
+     *
+     * 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.
+     *
+     * @param null|array $cfg
+     * @return Database
+     */
+    public static function getInstance($cfg = null) {
+        if (self::$handle == null) {
+            self::$handle = new Database($cfg);
+        }
+
+        return self::$handle;
+    }
+
+    /**
+     * <b>Diese Methode löscht alle Benutzer weg</b>
+     *
+     * Diese Methode sollte dann aufgerufen werden, wenn die Anwendung deployed wird
+     *
+     * @return bool
+     */
+    public function cleanup() {
+        try {
+            $this->pdo->exec("DELETE FROM t_user WHERE id > 2;");
+            $this->pdo->exec("DELETE FROM t_group WHERE id > 5;");
+
+            $this->pdo->exec("ALTER TABLE t_user AUTO_INCREMENT = 2;");
+            $this->pdo->exec("ALTER TABLE t_group AUTO_INCREMENT = 5;");
+        } catch (PDOException $pdoe) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     *
+     * @param string $table
+     * @param array $fields
+     * @param string $filename
+     * @param string $seperator
+     *
+     * @throws InvalidArgumentException
+     */
+    public function csvExport($table, $fields, $filename, $seperator = ';') {
+        $handle = fopen($filename, "w+");
+
+        if ($handle == FALSE) {
+            throw new InvalidArgumentException("Datei nicht gefunden: " . $filename);
+        }
+
+        $rows = $this->fetchAll(sprintf("SELECT %s FROM %s ORDER BY id", implode(", ", $fields), $table));
+
+        fwrite($handle, sprintf("%s\n", implode($seperator, $fields)));
+        foreach ($rows as $row) {
+            fwrite($handle, sprintf("%s\n", implode($seperator, $row)));
+        }
+
+        fclose($handle);
+    }
+
+    /**
+     * @param $table
+     * @param $cond
+     * @return array|null
+     */
+    public function fetchAll($table, $cond = 'id > 0') {
+        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $cond));
+
+        $stmt = $this->pdo->prepare(sprintf('
+            SELECT
+                *
+            FROM
+              %s
+            WHERE
+              %s
+            ', $table, $cond
+        ));
+
+        if ($stmt->execute()) {
+            return $stmt->fetchAll(PDO::FETCH_ASSOC);
+        }
+
+        return null;
+    }
+
+    /**
+     * @param $table
+     * @param $cond
+     * @return array|null
+     */
+    public function fetch($table, $cond = 'id > 0') {
+        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $cond));
+
+        $stmt = $this->pdo->prepare(sprintf('
+            SELECT
+                *
+            FROM
+              %s
+            WHERE
+              %s
+            LIMIT 1
+            ', $table, $cond
+        ));
+
+        if ($stmt->execute()) {
+            return $stmt->fetch(PDO::FETCH_ASSOC);
+        }
+
+        return null;
+    }
+
+    /**
+     *
+     * @param string $table
+     * @param string $filename
+     * @param string $seperator
+     *
+     * @throws InvalidArgumentException
+     */
+    public function csvImport($table, $filename, $seperator = ';') {
+        $handle = fopen($filename, "r");
+
+        if ($handle == FALSE) {
+            throw new InvalidArgumentException("Datei nicht gefunden: " . $filename);
+        }
+
+        $firstLine = trim(fgets($handle, 1024));
+        $firstExplodedLine = explode($seperator, $firstLine);
+        $firstImplodedLine = implode(", ", $firstExplodedLine);
+
+        while (($line = fgets($handle, 1024)) != NULL) {
+            $explodedLine = explode($seperator, trim($line));
+            $row = array();
+            foreach ($explodedLine as $explodedField) {
+                $row[] = "'$explodedField'";
+            }
+
+            $implodedLine = implode(", ", $row);
+            $this->pdo->exec(sprintf("INSERT INTO %s(id, %s) VALUES(NULL, %s);\n", $table, $firstImplodedLine, $implodedLine));
+        }
+
+        fclose($handle);
+    }
+
+    /**
+     * @param $table
+     * @param $id
+     * @return mixed|null
+     */
+    public function find($table, $id) {
+        $this->logger->info(sprintf('%s(%s, %d) ', __METHOD__, $table, $id));
+
+        $stmt = $this->pdo->prepare(
+                sprintf('
+              SELECT
+                *
+              FROM
+                %s
+              WHERE
+                id = :id
+              LIMIT 1
+            ', $table
+        ));
+
+        $stmt->bindParam(':id', $id);
+
+        $status = $stmt->execute();
+        if ($status) {
+            return $stmt->fetch(PDO::FETCH_ASSOC);
+        }
+
+        return null;
+    }
+
+    /**
+     * @param $table
+     * @param int $initial_id
+     * @return array|null
+     */
+    public function findAll($table, $initial_id = 0) {
+        $this->logger->info(sprintf('%s(%s, %d) ', __METHOD__, $table, $initial_id));
+
+        $stmt = $this->pdo->prepare(
+                sprintf('
+              SELECT
+                *
+              FROM
+                %s
+              WHERE
+                id > :id
+              ORDER BY ID ASC
+            ', $table
+        ));
+
+        $stmt->bindParam(':id', $initial_id);
+
+        if ($stmt->execute()) {
+            return $stmt->fetchAll(PDO::FETCH_ASSOC);
+        }
+
+        return null;
+    }
+
+    /**
+     * @param $table
+     * @param $field
+     * @param $value
+     * @return mixed|null
+     */
+    public function findByField($table, $field, $value) {
+        $this->logger->info(sprintf('%s(%s, %s, %s) ', __METHOD__, $table, $field, $value));
+
+        $stmt = $this->pdo->prepare(
+                sprintf('
+              SELECT
+                *
+              FROM
+                %s
+              WHERE
+                %s = :value
+              LIMIT 1
+            ', $table, $field
+        ));
+
+        $stmt->bindParam(':value', $value);
+
+        if ($stmt->execute()) {
+            return $stmt->fetch(PDO::FETCH_ASSOC);
+        }
+
+        return null;
+    }
+
+    /**
+     * @param $table
+     * @param $field
+     * @param $value
+     * @return array|null
+     */
+    function findAllByField($table, $field, $value) {
+        $this->logger->info(sprintf('%s(%s, %s, %s) ', __METHOD__, $table, $field, $value));
+
+        $stmt = $this->pdo->prepare(
+                sprintf('
+              SELECT
+                *
+              FROM
+                %s
+              WHERE
+                %s = :value
+            ', $table, $field
+        ));
+
+        $stmt->bindParam(':value', $value);
+
+        if ($stmt->execute()) {
+            return $stmt->fetchAll(PDO::FETCH_ASSOC);
+        }
+
+        return null;
+    }
+
+    /**
+     * @param $sql
+     * @return array|null
+     */
+    public function query($sql) {
+        $this->logger->info(sprintf('%s(%s) ', __METHOD__, $sql));
+
+        $stmt = $this->pdo->query($sql);
+
+        if ($stmt) {
+            return $stmt->fetchAll(PDO::FETCH_ASSOC);
+        }
+
+        return null;
+    }
+
+    /**
+     * @param $sql
+     * @return bool
+     */
+    public function execute($sql) {
+        return ($this->pdo->exec($sql) !== FALSE);
+    }
+
+    /**
+     * @param $table
+     * @param $array
+     * @return bool
+     */
+    public function persist($table, $array) {
+        $this->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->pdo->exec($sql) !== FALSE);
+    }
+
+    /**
+     * @param $table
+     * @param $id
+     * @param $array
+     * @return bool
+     */
+    public function store($table, $id, $array) {
+        $this->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->pdo->exec($sql) !== FALSE);
+    }
+
+    /**
+     * @param $table
+     * @param $id
+     * @return int
+     */
+    public function delete($table, $id) {
+        $this->logger->info(sprintf('%s(%s, %s) ', __METHOD__, $table, $id));
+
+        $sql = sprintf("
+            DELETE FROM %s
+            WHERE id = %d;
+        ", $table, $id);
+
+        return ($this->pdo->exec($sql) !== FALSE);
+    }
+
+    public function getLastInsertedId() {
+        return $this->pdo->lastInsertId();
+    }
+
+    public function getLastError() {
+        return $this->pdo->errorCode();
+    }
+
+    /**
+     *
+     * @param string $string
+     * @return string
+     */
+    public function quote($string) {
+        return $this->pdo->quote($string);
+    }
+
+}