From dff9c0b2af164d3a53dadedc77d65a3224455e93 Mon Sep 17 00:00:00 2001 From: Alexander Demidov Date: Fri, 20 Sep 2013 22:11:54 +0400 Subject: [PATCH] Refactoring SqlCriteria, SqlModel. Add SqlResultProvider.fetchField(). --- model/SqlCriteria.php | 45 ++++++++++++++++++++++----- model/SqlDbDriver.php | 49 +++++++++++++++++++++++++++-- model/SqlModel.php | 75 +++++++++++++++++++++------------------------ model/SqlResultProvider.php | 5 +++ 4 files changed, 125 insertions(+), 49 deletions(-) diff --git a/model/SqlCriteria.php b/model/SqlCriteria.php index 0afbf8c..9f18fd4 100644 --- a/model/SqlCriteria.php +++ b/model/SqlCriteria.php @@ -17,12 +17,20 @@ class SqlCriteria */ private $model; + private $sql_expression; + + private $sql_expression_params = array(); + /** * @param $model SqlModel + * @param $sql_expression string|null Sql expression with SELECT and FROM operators. If fetched, then SqlCriteria::select(), SqlCriteria::distinct() disabled for use. + * @param $sql_expression_params array additional params to be replaced in sql expression */ - public function __construct($model) + public function __construct($model, $sql_expression = null, $sql_expression_params = array()) { $this->model = $model; + $this->sql_expression = $sql_expression; + $this->sql_expression_params = $sql_expression_params; } /** @@ -30,22 +38,45 @@ class SqlCriteria */ public function find() { - return $this->model->find($this->select, $this->distinct, $this->where, $this->order, $this->limit); + return $this->model->find($this->select, $this->distinct, $this->where, $this->order, $this->limit, null, null, $this->sql_expression, $this->sql_expression_params); + } + + public function count() + { + return $this->model->find(new DbExpr('COUNT(*) as count'), '', $this->where, null, null, null, null, $this->sql_expression, $this->sql_expression_params)->fetchField('count'); } /** - * @param $cond string Condition with "?" placeholder @ex 'field=?' - * @param $value string|array|DbExpr Value. Array transformed to DbExpr(implode(',' Array)) All elements in the array mast be integer + * @param $cond string|array Condition with "?" placeholder @ex 'field=?' or 'field=1' or array('field=?' => 1', 'field=1') + * @param $value string|array|DbExpr|null Value. Array transformed to DbExpr(implode(',' Array)) All elements in the array mast be integer * @return SqlCriteria * @desc Allow multiple calls */ - public function where($cond, $value) + public function where($cond, $value = null) { - $this->where[$cond] = $value; + if (is_null($value)) { + if (is_array($cond)) { + $this->where = $this->where + $cond; + } else { + $this->where[] = $cond; + } + } else { + $this->where[$cond] = $value; + } return $this; } /** + * @param $field string + * @param $value array + * @return SqlCriteria + */ + public function whereIn($field, $value) + { + return $this->where($field . ' in ?', $value); + } + + /** * @param $field string Field @ex 'field' * @param $order_desc bool Descendant sort direction * @return SqlCriteria @@ -85,7 +116,7 @@ class SqlCriteria } /** - * @param $field string + * @param $field string|bool If true then distinct by * * @return SqlCriteria */ public function distinct($field) diff --git a/model/SqlDbDriver.php b/model/SqlDbDriver.php index 4714578..d45119a 100644 --- a/model/SqlDbDriver.php +++ b/model/SqlDbDriver.php @@ -127,9 +127,9 @@ abstract class SqlDbDriver extends DbDriver /** * @param mixed $where * @return string - * TODO: Если cond Это int и term Это тоже int - кидать Exception (иначе эта ошибка повлечет обновление всех записей в таблице + * @throws ErrorException */ - protected function whereExpr($where) + public function whereExpr($where) { if (empty($where)) { return $where; @@ -140,16 +140,61 @@ abstract class SqlDbDriver extends DbDriver } foreach ($where as $cond => &$term) { if (is_int($cond)) { + if (is_int($term)) { + throw new ErrorException('Condition in where expression as integer. Dangerous. ' . $term); + } if ($term instanceof DbExpr) { $term = (string) $term; } } else { + if (is_array($term)) { + $term = new DbExpr('(' . implode(',', array_map(function($item){return intval($item);}, $term)) . ')'); + } $term = $this->quoteInto($cond, $term); } } return implode(' AND ', $where); } + /** + * @param $select array + * @param $distinct string|bool + * @return string + */ + public function selectExpr($select, $distinct = false) + { + if (empty($distinct) && empty($select)) { + return '*'; + } + if (!is_array($select)) { + $select = array($select); + } + if ($distinct) { + $distinct = ((is_bool($distinct)) ? '*' : $this->quoteIdentifier($distinct)); + array_unshift($select, new DbExpr('DISTINCT ' . $distinct)); + } + foreach ($select as $field => &$term) { + if (is_int($field)) { + if ($term instanceof DbExpr) { + $term = (string) $term; + } else { + $term = $this->quoteIdentifier($term); + } + } else { + $term = $this->quoteIdentifier($field) . ' as ' . $this->quoteIdentifier($term); + } + } + return implode(',', $select); + } + + public function limitExpr($limit) + { + if (empty($limit)) { + return $limit; + } + return implode(',',array_map(function($item){return intval($item);},explode(',',$limit))); + } + abstract protected function driverQuote($value); abstract protected function driverBeginTransaction(); diff --git a/model/SqlModel.php b/model/SqlModel.php index a284786..588725e 100644 --- a/model/SqlModel.php +++ b/model/SqlModel.php @@ -50,8 +50,8 @@ abstract class SqlModel extends Model */ public function update($data, $where) { - if (is_int($where) || $where === (string) (int) $where) { - $where = $this->identify($this->key) . '=' . (int) $where; + if (is_int($where) || $where === (string)(int)$where) { + $where = $this->identify($this->key) . '=' . (int)$where; } return parent::update($data, $where); } @@ -62,7 +62,7 @@ abstract class SqlModel extends Model */ public function delete($id) { - $where = $this->identify($this->key) . '=' . (int) $id; + $where = $this->identify($this->key) . '=' . (int)$id; return $this->db->delete($this->table(), $where); } @@ -87,7 +87,7 @@ abstract class SqlModel extends Model for ($i = 0; $i < count($params['sort']); $i++) { $order = (isset($params['order'][$params['sort'][$i]]) && $params['order'][$params['sort'][$i]] == 'desc') ? 'DESC' : 'ASC'; if (in_array($params['sort'][$i], $sortable)) { - $order_list[] = $this->identify($params['sort'][$i]) . ' ' . $order; + $order_list[] = $this->identify($params['sort'][$i]) . ' ' . $order; } } if ($order_list) { @@ -112,7 +112,7 @@ abstract class SqlModel extends Model if ($table_prefix) { $sql = $table_prefix . '.'; } - $sql .= $this->identify($params['qt']) . ' LIKE ' . $this->quote('%' . $params['q'] . '%'); + $sql .= $this->identify($params['qt']) . ' LIKE ' . $this->quote('%' . $params['q'] . '%'); } return $sql; } @@ -189,48 +189,43 @@ abstract class SqlModel extends Model return $result; } - - public function find($select, $distinct, $where, $order, $limit) + /** + * @param $select array + * @param $distinct string|bool + * @param $where array @ex array('field=?' => $value, 'field=1') + * @param $order array @ex array('sort' => array('field1', 'field2'), 'order' => array('field2' => 'desc')) + * @param $limit string @ex '30' or '30,30' + * @param $heaving TODO + * @param $group_by TODO + * @param $sql_expression null|string + * @param $sql_expression_params array + * @param $cache_key CacheKey|null + * @return SqlResultProvider + */ + public function find($select, $distinct, $where, $order, $limit, $heaving = null, $group_by = null, $sql_expression = null, $sql_expression_params = array(), $cache_key = null) { - if (!$select) { - $select = array(new DbExpr('*')); - } - foreach ($select as $field => &$term) { - if (is_int($field)) { - if ($term instanceof DbExpr) { - $term = (string) $term; - } else { - $term = $this->db->quoteIdentifier($term); - } - } else { - $term = $this->db->quoteIdentifier($field) . ' as ' . $this->db->quoteIdentifier($term); - } - } - foreach ($where as $cond => &$term) { - if (is_array($term)) { - $term = new DbExpr('(' . implode(',', array_map(function($item){return intval($item);}, $term)) . ')'); - } - $term = $this->db->quoteInto($cond, $term); - } - if ($distinct != '') { - $distinct = 'DISTINCT ' . $this->db->quoteIdentifier($distinct); - } - if ($limit != '') { - $limit = implode(',',array_map(function($item){return intval($item);},explode(',',$limit))); - } - $result_items = parent::fetchAll('SELECT ' . (($distinct) ? $distinct : implode(',', $select)) - . ' FROM ' . $this->table() - . (($where) ? (' WHERE ' . implode(' AND ', $where)) : '') - . (($order) ? ($this->order($order, $order['sort'])) : '') - . (($limit) ? (' LIMIT ' . $limit) : '')); + $select = $this->db->selectExpr($select, $distinct); + $where = $this->db->whereExpr($where); + $order = isset($order['sort']) ? $this->order($order, $order['sort']) : false; + $limit = $this->db->limitExpr($limit); + $result_items = parent::fetchAll( + (($sql_expression) ? $sql_expression : ('SELECT ' . $select . ' FROM ' . $this->table())) + . (($where) ? (' WHERE ' . $where) : '') + . (($order) ? ($order) : '') + . (($limit) ? (' LIMIT ' . $limit) : ''), + $sql_expression_params, + $cache_key + ); return new SqlResultProvider($result_items); } /** + * @param $sql_expression null + * @param $sql_expression_params array * @return SqlCriteria */ - public function criteria() + public function criteria($sql_expression = null, $sql_expression_params = array()) { - return new SqlCriteria(); + return new SqlCriteria($this, $sql_expression, $sql_expression_params); } } \ No newline at end of file diff --git a/model/SqlResultProvider.php b/model/SqlResultProvider.php index f8d3de9..ff9f3b8 100644 --- a/model/SqlResultProvider.php +++ b/model/SqlResultProvider.php @@ -64,6 +64,11 @@ class SqlResultProvider return $this->result_items[$key]; } + public function fetchField($field) + { + return current($this->result_items)->{$field}; + } + public function fetch() { return current($this->result_items);