diff --git a/PHASE_3_TRACKER.md b/PHASE_3_TRACKER.md index 9405aeb..42dbd03 100644 --- a/PHASE_3_TRACKER.md +++ b/PHASE_3_TRACKER.md @@ -10,8 +10,8 @@ - [x] Context.php Erweiterung (getContext, cloneContext, updateCustomer, getTranslator, getTranslatorFromLocale, getComputingPrecision, Device-Erkennung, Mobile-Erkennung) - [x] Cart.php Erweiterung (nbProducts, getNbProducts, addCartRule, getProductQuantity, updateQty, deleteProduct, getOrderTotal, getTotalWeight, isVirtualCart, hasProducts, hasRealProducts, getCarrierCost, getGiftWrappingPrice, lastNoneOrderedCart, getCustomerCarts, checkQuantities, getProducts, getDiscounts) -### Sprint 1.2: Datenbank & ORM (0% abgeschlossen) -- [ ] Db.php Erweiterung +### Sprint 1.2: Datenbank & ORM (25% abgeschlossen) +- [x] Db.php Erweiterung (query, insert, update, delete, execute, executeS, getRow, getValue, numRows, escape, checkConnection, checkEncoding, hasTableWithSamePrefix, checkCreatePrivilege, checkSelectPrivilege) - [ ] ObjectModel.php Erweiterung - [ ] Database Schema Erweiterung - [ ] Migration System @@ -122,10 +122,10 @@ - [ ] Monitoring Setup - [ ] Backup Setup -## Gesamtfortschritt: 17% (1 von 18 Sprints abgeschlossen) +## Gesamtfortschritt: 19% (1.25 von 18 Sprints abgeschlossen) ### Nächste Schritte: -1. Sprint 1.2 beginnen (Datenbank & ORM) -2. Db.php Erweiterung -3. ObjectModel.php Erweiterung -4. Database Schema Erweiterung \ No newline at end of file +1. ObjectModel.php Erweiterung +2. Database Schema Erweiterung +3. Migration System +4. Sprint 1.2 abschließen \ No newline at end of file diff --git a/classes/Db.php b/classes/Db.php new file mode 100644 index 0000000..6d0a692 --- /dev/null +++ b/classes/Db.php @@ -0,0 +1,686 @@ +server = $server; + $this->user = $user; + $this->password = $password; + $this->database = $database; + $this->is_cache_enabled = _PS_CACHE_ENABLED_; + + if ($connect) { + $this->connect(); + } + } + + /** + * Disable cache + */ + public function disableCache() + { + $this->is_cache_enabled = false; + } + + /** + * Enable cache + */ + public function enableCache() + { + $this->is_cache_enabled = true; + } + + /** + * Execute query + * + * @param string $sql + * @return bool + */ + public function query($sql) + { + if ($sql instanceof DbQuery) { + $sql = $sql->build(); + } + + $this->result = $this->_query($sql); + + if (!$this->result && $this->getNumberError() == 2006) { + $this->connect(); + $this->result = $this->_query($sql); + } + + if (_PS_DEBUG_SQL_) { + $this->displayError($sql); + } + + return $this->result; + } + + /** + * Execute INSERT query + * + * @param string $table + * @param array $data + * @param bool $null_values + * @param bool $use_cache + * @param int $type + * @param bool $add_prefix + * @return bool + */ + public function insert($table, $data, $null_values = false, $use_cache = true, $type = self::INSERT, $add_prefix = true) + { + if (!$data && !$null_values) { + return true; + } + + if ($add_prefix) { + $table = _DB_PREFIX_ . $table; + } + + if ($type == self::INSERT) { + $insert_keyword = 'INSERT'; + } elseif ($type == self::INSERT_IGNORE) { + $insert_keyword = 'INSERT IGNORE'; + } elseif ($type == self::REPLACE) { + $insert_keyword = 'REPLACE'; + } elseif ($type == self::ON_DUPLICATE_KEY) { + $insert_keyword = 'INSERT'; + } else { + throw new Exception('Bad keyword, must be Db::INSERT or Db::INSERT_IGNORE or Db::REPLACE or Db::ON_DUPLICATE_KEY'); + } + + // Check if $data is a list of row + $current = current($data); + if (!is_array($current) || isset($current['type'])) { + $data = [$data]; + } + + $keys = []; + $values_stringified = []; + $first_loop = true; + $duplicate_key_stringified = ''; + + foreach ($data as $row_data) { + $values = []; + foreach ($row_data as $key => $value) { + if (!$first_loop) { + if (!in_array("`$key`", $keys)) { + throw new Exception('Keys form $data subarray don\'t match'); + } + if ($duplicate_key_stringified != '') { + throw new Exception('On duplicate key cannot be used on insert with more than 1 VALUE group'); + } + } else { + $keys[] = '`' . $this->escape($key) . '`'; + } + + if (!is_array($value)) { + $value = ['type' => 'text', 'value' => $value]; + } + if ($value['type'] == 'sql') { + $values[] = $string_value = $value['value']; + } else { + $values[] = $string_value = $null_values && ($value['value'] === '' || null === $value['value']) ? 'NULL' : "'{$value['value']}'"; + } + + if ($type == self::ON_DUPLICATE_KEY) { + $duplicate_key_stringified .= '`' . $this->escape($key) . '` = ' . $string_value . ','; + } + } + $first_loop = false; + $values_stringified[] = '(' . implode(', ', $values) . ')'; + } + $keys_stringified = implode(', ', $keys); + + $sql = $insert_keyword . ' INTO `' . $table . '` (' . $keys_stringified . ') VALUES ' . implode(', ', $values_stringified); + if ($type == self::ON_DUPLICATE_KEY) { + $sql .= ' ON DUPLICATE KEY UPDATE ' . substr($duplicate_key_stringified, 0, -1); + } + + return (bool) $this->q($sql, $use_cache); + } + + /** + * Execute UPDATE query + * + * @param string $table + * @param array $data + * @param string $where + * @param int $limit + * @param bool $null_values + * @param bool $use_cache + * @param bool $add_prefix + * @return bool + */ + public function update($table, $data, $where = '', $limit = 0, $null_values = false, $use_cache = true, $add_prefix = true) + { + if (!$data) { + return true; + } + + if ($add_prefix) { + $table = _DB_PREFIX_ . $table; + } + + $sql = 'UPDATE `' . $this->escape($table) . '` SET '; + foreach ($data as $key => $value) { + if (!is_array($value)) { + $value = ['type' => 'text', 'value' => $value]; + } + if ($value['type'] == 'sql') { + $sql .= '`' . $this->escape($key) . "` = {$value['value']},"; + } else { + $sql .= ($null_values && ($value['value'] === '' || null === $value['value'])) ? '`' . $this->escape($key) . '` = NULL,' : '`' . $this->escape($key) . "` = '{$value['value']}',"; + } + } + + $sql = rtrim($sql, ','); + if ($where) { + $sql .= ' WHERE ' . $where; + } + if ($limit) { + $sql .= ' LIMIT ' . (int) $limit; + } + + return (bool) $this->q($sql, $use_cache); + } + + /** + * Execute DELETE query + * + * @param string $table + * @param string $where + * @param int $limit + * @param bool $use_cache + * @param bool $add_prefix + * @return bool + */ + public function delete($table, $where = '', $limit = 0, $use_cache = true, $add_prefix = true) + { + if ($add_prefix) { + $table = _DB_PREFIX_ . $table; + } + + $this->result = false; + $sql = 'DELETE FROM `' . $this->escape($table) . '`' . ($where ? ' WHERE ' . $where : '') . ($limit ? ' LIMIT ' . (int) $limit : ''); + $res = $this->query($sql); + if ($use_cache && $this->is_cache_enabled) { + Cache::getInstance()->deleteQuery($sql); + } + + return (bool) $res; + } + + /** + * Execute query + * + * @param string|DbQuery $sql + * @param bool $use_cache + * @return bool + */ + public function execute($sql, $use_cache = true) + { + if ($sql instanceof DbQuery) { + $sql = $sql->build(); + } + + $this->result = $this->query($sql); + if ($use_cache && $this->is_cache_enabled) { + Cache::getInstance()->deleteQuery($sql); + } + + return (bool) $this->result; + } + + /** + * Execute query and return all results + * + * @param string|DbQuery $sql + * @param bool $array + * @param bool $use_cache + * @return array + */ + public function executeS($sql, $array = true, $use_cache = true) + { + if ($sql instanceof DbQuery) { + $sql = $sql->build(); + } + + $this->result = $this->query($sql); + if (!$this->result) { + return []; + } + + $result = $this->getAll($this->result); + if ($use_cache && $this->is_cache_enabled) { + Cache::getInstance()->deleteQuery($sql); + } + + return $result; + } + + /** + * Get single row + * + * @param string|DbQuery $sql + * @param bool $use_cache + * @return array|false + */ + public function getRow($sql, $use_cache = true) + { + if ($sql instanceof DbQuery) { + $sql = $sql->build(); + } + + $this->result = $this->query($sql); + if (!$this->result) { + return false; + } + + $result = $this->nextRow($this->result); + if ($use_cache && $this->is_cache_enabled) { + Cache::getInstance()->deleteQuery($sql); + } + + return $result; + } + + /** + * Get single value + * + * @param string|DbQuery $sql + * @param bool $use_cache + * @return string|false + */ + public function getValue($sql, $use_cache = true) + { + if ($sql instanceof DbQuery) { + $sql = $sql->build(); + } + + $this->result = $this->query($sql); + if (!$this->result) { + return false; + } + + $result = $this->nextRow($this->result); + if ($use_cache && $this->is_cache_enabled) { + Cache::getInstance()->deleteQuery($sql); + } + + if (!$result) { + return false; + } + + return reset($result); + } + + /** + * Get number of rows + * + * @return int + */ + public function numRows() + { + if (!$this->result) { + return 0; + } + + return $this->_numRows($this->result); + } + + /** + * Protected query method + * + * @param string $sql + * @param bool $use_cache + * @return bool + */ + protected function q($sql, $use_cache = true) + { + $this->result = $this->query($sql); + if ($use_cache && $this->is_cache_enabled) { + Cache::getInstance()->deleteQuery($sql); + } + + return (bool) $this->result; + } + + /** + * Display error + * + * @param bool|string $sql + */ + public function displayError($sql = false) + { + if (_PS_DEBUG_SQL_) { + $error = $this->getMsgError(); + if ($sql) { + $error .= ' - SQL: ' . $sql; + } + echo '
' . $error . '
'; + } + } + + /** + * Escape string + * + * @param string $string + * @param bool $html_ok + * @param bool $bq_sql + * @return string + */ + public function escape($string, $html_ok = false, $bq_sql = false) + { + if (_PS_MAGIC_QUOTES_GPC_) { + $string = stripslashes($string); + } + + if (!$html_ok) { + $string = strip_tags(Tools::nl2br($string)); + } + + if (!$bq_sql) { + $string = str_replace('`', '\`', $string); + } + + return $this->_escape($string); + } + + /** + * Check database connection + * + * @param string $server + * @param string $user + * @param string $pwd + * @param string $db + * @param bool $new_db_link + * @param string|null $engine + * @param int $timeout + * @return bool + */ + public static function checkConnection($server, $user, $pwd, $db, $new_db_link = true, $engine = null, $timeout = 5) + { + $class = self::getClass(); + return $class::checkConnection($server, $user, $pwd, $db, $new_db_link, $engine, $timeout); + } + + /** + * Check encoding + * + * @param string $server + * @param string $user + * @param string $pwd + * @return bool + */ + public static function checkEncoding($server, $user, $pwd) + { + $class = self::getClass(); + return $class::checkEncoding($server, $user, $pwd); + } + + /** + * Check if table with same prefix exists + * + * @param string $server + * @param string $user + * @param string $pwd + * @param string $db + * @param string $prefix + * @return bool + */ + public static function hasTableWithSamePrefix($server, $user, $pwd, $db, $prefix) + { + $class = self::getClass(); + return $class::hasTableWithSamePrefix($server, $user, $pwd, $db, $prefix); + } + + /** + * Check create privilege + * + * @param string $server + * @param string $user + * @param string $pwd + * @param string $db + * @param string $prefix + * @param string|null $engine + * @return bool + */ + public static function checkCreatePrivilege($server, $user, $pwd, $db, $prefix, $engine = null) + { + $class = self::getClass(); + return $class::checkCreatePrivilege($server, $user, $pwd, $db, $prefix, $engine); + } + + /** + * Check select privilege + * + * @param string $server + * @param string $user + * @param string $pwd + * @param string $db + * @param string $prefix + * @param string|null $engine + * @return bool + */ + public static function checkSelectPrivilege($server, $user, $pwd, $db, $prefix, $engine = null) + { + $class = self::getClass(); + return $class::checkSelectPrivilege($server, $user, $pwd, $db, $prefix, $engine); + } + + /** + * Get link + * + * @return PDO|mysqli|resource|null + */ + public function getLink() + { + return $this->link; + } +} \ No newline at end of file