From daff11df6b3f2a90b64ee2ea86161b1632c357f7 Mon Sep 17 00:00:00 2001 From: rMalie Date: Tue, 20 Sep 2011 16:49:22 +0000 Subject: [PATCH] // Improve DbQuery --- classes/Cart.php | 20 ++-- classes/Product.php | 2 +- classes/db/DbPDO.php | 186 +++++++++++++++++++++++++++++++++++ classes/db/DbQuery.php | 216 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 413 insertions(+), 11 deletions(-) create mode 100644 classes/db/DbPDO.php create mode 100644 classes/db/DbQuery.php diff --git a/classes/Cart.php b/classes/Cart.php index 50b4c6d9f..c2e4816c6 100644 --- a/classes/Cart.php +++ b/classes/Cart.php @@ -376,18 +376,18 @@ class CartCore extends ObjectModel ->select('CONCAT(cp.`id_product`, cp.`id_product_attribute`) AS unique_id'); // Build FROM - $sql->from(_DB_PREFIX_.'cart_product cp'); + $sql->from('cart_product cp'); // Build JOIN - $sql->leftJoin(_DB_PREFIX_.'product p', 'p.`id_product` = cp.`id_product`') - ->leftJoin(_DB_PREFIX_.'product_lang pl', 'p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$this->id_lang.Context::getContext()->shop->sqlLang('pl')) - ->leftJoin(_DB_PREFIX_.'tax_rule tr', 'p.`id_tax_rules_group` = tr.`id_tax_rules_group` + $sql->leftJoin('product p ON p.`id_product` = cp.`id_product`') + ->leftJoin('product_lang pl ON p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$this->id_lang.Context::getContext()->shop->sqlLang('pl')) + ->leftJoin('tax_rule tr ON p.`id_tax_rules_group` = tr.`id_tax_rules_group` AND tr.`id_country` = '.(int)$id_country.' AND tr.`id_state` = 0 AND tr.`zipcode_from` = 0') - ->leftJoin(_DB_PREFIX_.'tax t', 't.`id_tax` = tr.`id_tax`') - ->leftJoin(_DB_PREFIX_.'tax_lang tl', 't.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int)$this->id_lang) - ->leftJoin(_DB_PREFIX_.'category_lang cl', 'p.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int)$this->id_lang.Context::getContext()->shop->sqlLang('cl')); + ->leftJoin('tax t ON t.`id_tax` = tr.`id_tax`') + ->leftJoin('tax_lang tl ON t.`id_tax` = tl.`id_tax` AND tl.`id_lang` = '.(int)$this->id_lang) + ->leftJoin('category_lang cl ON p.`id_category_default` = cl.`id_category` AND cl.`id_lang` = '.(int)$this->id_lang.Context::getContext()->shop->sqlLang('cl')); // @todo test if everything is ok, then refactorise call of this method Product::sqlStock('cp', 'cp', false, null, $sql); @@ -407,7 +407,7 @@ class CartCore extends ObjectModel if (Customization::isFeatureActive()) { $sql->select('cu.`id_customization`, cu.`quantity` AS customization_quantity'); - $sql->leftJoin(_DB_PREFIX_.'customization` cu ON (p.`id_product` = cu.`id_product`)'); + $sql->leftJoin('customization cu ON p.`id_product` = cu.`id_product`'); } if (Combination::isFeatureActive()) @@ -419,8 +419,8 @@ class CartCore extends ObjectModel ->select('IF (IFNULL(pa.`ean13`, \'\') = \'\', p.`ean13`, pa.`ean13`) AS ean13, IF (IFNULL(pa.`upc`, \'\') = \'\', p.`upc`, pa.`upc`) AS upc') ->select('pai.`id_image` as pai_id_image, IFNULL(pa.`minimal_quantity`, p.`minimal_quantity`) as minimal_quantity, pa.`ecotax` AS ecotax_attr'); - $sql->leftJoin(_DB_PREFIX_.'product_attribute pa', 'pa.`id_product_attribute` = cp.`id_product_attribute`') - ->leftJoin(_DB_PREFIX_.'product_attribute_image pai', 'pai.`id_product_attribute` = pa.`id_product_attribute`'); + $sql->leftJoin('product_attribute pa ON pa.`id_product_attribute` = cp.`id_product_attribute`') + ->leftJoin('product_attribute_image pai ON pai.`id_product_attribute` = pa.`id_product_attribute`'); } else $sql->select('p.`reference` AS reference, p.`supplier_reference` AS supplier_reference, p.`ean13`, p.`upc` AS upc, p.`minimal_quantity` AS minimal_quantity'); diff --git a/classes/Product.php b/classes/Product.php index c5465ec66..215b6004e 100644 --- a/classes/Product.php +++ b/classes/Product.php @@ -2065,7 +2065,7 @@ class ProductCore extends ObjectModel { // @todo remove this code when query builder is accepted or removed $method = ($innerJoin) ? 'innerJoin' : 'leftJoin'; - $sql->$method(_DB_PREFIX_.'stock stock', 'stock.id_product = '.pSQL($productAlias).'.id_product'); + $sql->$method('stock stock ON stock.id_product = '.pSQL($productAlias).'.id_product'); if (!is_null($productAttribute)) { if (!Combination::isFeatureActive()) diff --git a/classes/db/DbPDO.php b/classes/db/DbPDO.php new file mode 100644 index 000000000..1cefc61a3 --- /dev/null +++ b/classes/db/DbPDO.php @@ -0,0 +1,186 @@ + +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +/** + * This class is currently only here for tests + * + * @since 1.5.0 + */ +class DbPDOCore extends Db +{ + /** + * @see DbCore::connect() + */ + public function connect() + { + try + { + $this->_link = new PDO('mysql:dbname='.$this->_database.';host='.$this->_server, $this->_user, $this->_password); + } + catch (PDOException $e) + { + die(Tools::displayError('Link to database cannot be established. ('.$e->getMessage().')')); + } + + // UTF-8 support + if ($this->_link->exec('SET NAMES \'utf8\'') === false) + die(Tools::displayError('PrestaShop Fatal error: no utf-8 support. Please check your server configuration.')); + + return $this->_link; + } + + /** + * @see DbCore::disconnect() + */ + public function disconnect() + { + unset($this->_link); + } + + /** + * @see DbCore::_query() + */ + protected function _query($sql) + { + return $this->_link->query($sql); + } + + /** + * @see DbCore::nextRow() + */ + public function nextRow($result = false) + { + if (!$result) + $result = $this->_result; + return $result->fetch(); + } + + /** + * @see DbCore::_numRows() + */ + protected function _numRows($result) + { + return $result->rowCount();; + } + + /** + * @see DbCore::Insert_ID() + */ + public function Insert_ID() + { + return $this->_link->lastInsertId(); + } + + /** + * @see DbCore::Affected_Rows() + */ + public function Affected_Rows() + { + return $this->_result->rowCount(); + } + + /** + * @see DbCore::getMsgError() + */ + public function getMsgError($query = false) + { + $error = $this->_link->errorInfo(); + return $error[2]; + } + + /** + * @see DbCore::getNumberError() + */ + public function getNumberError() + { + $error = $this->_link->errorInfo(); + return $error[1]; + } + + /** + * @see DbCore::getVersion() + */ + public function getVersion() + { + return $this->getValue('SELECT VERSION()'); + } + + /** + * @see DbCore::_escape() + */ + public function _escape($str) + { + $search = array("\\", "\0", "\n", "\r", "\x1a", "'", '"'); + $replace = array("\\\\", "\\0", "\\n", "\\r", "\Z", "\'", '\"'); + + return str_replace($search, $replace, $str); + } + + /** + * @see DbCore::set_db() + */ + public function set_db($db_name) + { + return $this->_link->exec('USE '.pSQL($db_name)); + } + + /** + * @see DbCore::tryToConnect() + */ + static public function tryToConnect($server, $user, $pwd, $db) + { + try + { + $test = new PDO('mysql:dbname='.$db.';host='.$server, $user, $pwd); + } + catch (PDOException $e) + { + return 1; + } + unset($test); + return 0; + } + + /** + * @see DbCore::tryUTF8() + */ + static public function tryUTF8($server, $user, $pwd) + { + try + { + $test = new PDO('mysql:dbname='.$db.';host='.$server, $user, $pwd); + } + catch (PDOException $e) + { + return false; + } + $result = $test->exec('SET NAMES \'utf8\''); + unset($test); + + return ($result === false) ? false : true; + } +} diff --git a/classes/db/DbQuery.php b/classes/db/DbQuery.php new file mode 100644 index 000000000..bc3d6240c --- /dev/null +++ b/classes/db/DbQuery.php @@ -0,0 +1,216 @@ + +* @copyright 2007-2011 PrestaShop SA +* @version Release: $Revision$ +* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) +* International Registered Trademark & Property of PrestaShop SA +*/ + +/** + * SQL query builder + * + * @since 1.5.0 + */ +class DbQueryCore +{ + /** + * @var array list of data to build the query + */ + protected $query = array( + 'select' => array(), + 'from' => '', + 'join' => array(), + 'where' => array(), + 'group' => array(), + 'having' => array(), + 'order' => array(), + 'limit' => array('offset' => 0, 'limit' => 0), + ); + + /** + * Add fields in query selection + * + * @param string $fields List of fields to concat to other fields + * @return DbQuery + */ + public function select($fields) + { + $this->query['select'][] = $fields; + return $this; + } + + /** + * Set table for FROM clause + * + * @param string $table Table name + * @return DbQuery + */ + public function from($table) + { + $this->query['from'] = _DB_PREFIX_.$table; + return $this; + } + + /** + * Add JOIN clause + * + * @param string $type Join type : left|right|inner|cross|union|natural + * @return DbQuery + */ + public function join($type, $join) + { + $type = strtolower($type); + $types = array( + 'left' => 'LEFT JOIN', + 'right' => 'RIGHT JOIN', + 'inner' => 'INNER JOIN', + 'cross' => 'CROSS JOIN', + 'union' => 'UNION JOIN', + 'natural' => 'NATURAL JOIN', + ); + + if (!isset($types[$type])) + die('Bad type in DbQuery->join()'); + + $this->query['join'][] = $types[$type].' '._DB_PREFIX_.$join; + return $this; + } + + public function leftJoin($join) + { + return $this->join('left', $join); + } + + public function innerJoin($table) + { + return $this->join('inner', $join); + } + + /** + * Add a restriction in WHERE clause (each restriction will be separated by AND statement) + * + * @param string $restriction + * @return DbQuery + */ + public function where($restriction) + { + $this->query['where'][] = $restriction; + return $this; + } + + /** + * Add a restriction in HAVING clause (each restriction will be separated by AND statement) + * + * @param string $restriction + * @return DbQuery + */ + public function having($restriction) + { + $this->query['having'][] = $restriction; + return $this; + } + + /** + * Add an ORDER B restriction + * + * @param string $fields List of fields to sort. E.g. $this->order('myField, b.mySecondField DESC') + * @return DbQuery + */ + public function order($fields) + { + $this->query['order'][] = $fields; + return $this; + } + + /** + * Add a GROUP BY restriction + * + * @param string $fields List of fields to sort. E.g. $this->group('myField, b.mySecondField DESC') + * @return DbQuery + */ + public function group($fields) + { + $this->query['group'][] = $fields; + return $this; + } + + /** + * Limit results in query + * + * @param string $fields List of fields to sort. E.g. $this->order('myField, b.mySecondField DESC') + * @return DbQuery + */ + public function limit($limit, $offset = 0) + { + $offset = (int)$offset; + if ($offset < 0) + $offset = 0; + + $this->query['limit'] = array( + 'offset' => $offset, + 'limit' => (int)$limit, + ); + return $this; + } + + /** + * Generate and get the query + * + * @return string + */ + public function build() + { + $sql = 'SELECT '.((($this->query['select'])) ? implode(",\n", $this->query['select']) : '*')."\n"; + + if (!$this->query['from']) + die('DbQuery->build() missing from clause'); + $sql .= 'FROM '.$this->query['from']."\n"; + + if ($this->query['join']) + $sql .= implode("\n", $this->query['join'])."\n"; + + if ($this->query['where']) + $sql .= 'WHERE '.implode(' AND ', $this->query['where'])."\n"; + + if ($this->query['group']) + $sql .= 'GROUP BY '.implode(', ', $this->query['group'])."\n"; + + if ($this->query['having']) + $sql .= 'HAVING '.implode(' AND ', $this->query['having'])."\n"; + + if ($this->query['order']) + $sql .= 'ORDER BY '.implode(', ', $this->query['order'])."\n"; + + if ($this->query['limit']['limit']) + { + $limit = $this->query['limit']; + $sql .= 'LIMIT '.(($limit['offset']) ? $limit['offset'].', '.$limit['limit'] : $limit['limit']); + } + + return $sql; + } + + public function __toString() + { + return $this->build(); + } +} \ No newline at end of file