diff --git a/library/think/db/Builder.php b/library/think/db/Builder.php index 6f6bca22..0ddaca79 100644 --- a/library/think/db/Builder.php +++ b/library/think/db/Builder.php @@ -108,7 +108,7 @@ abstract class Builder * value分析 * @access protected * @param mixed $value - * @return string + * @return string|array */ protected function parseValue($value) { @@ -215,10 +215,9 @@ abstract class Builder } if ($value instanceof \Closure) { // 使用闭包查询 - $class = clone $this->query; - $class->options([]); - call_user_func_array($value, [ & $class]); - $str[] = ' ' . $key . ' ( ' . $this->buildWhere($class->getOptions('where'), $table) . ' )'; + $query = new Query($this->connection); + call_user_func_array($value, [ & $query]); + $str[] = ' ' . $key . ' ( ' . $this->buildWhere($query->getOptions('where'), $table) . ' )'; } else { if (strpos($field, '|')) { // 不同字段使用相同查询条件(OR) @@ -313,10 +312,9 @@ abstract class Builder // 执行闭包子查询 protected function parseClosure($call, $show = true) { - $class = clone $this->query; - $class->options([]); - call_user_func_array($call, [ & $class]); - return $class->buildSql($show); + $query = new Query($this->connection); + call_user_func_array($call, [ & $query]); + return $query->buildSql($show); } /** @@ -461,6 +459,7 @@ abstract class Builder /** * 设置锁机制 * @access protected + * @param bool $locl * @return string */ protected function parseLock($lock = false) @@ -484,18 +483,6 @@ abstract class Builder $offset = $listRows * ($page - 1); $options['limit'] = $offset . ',' . $listRows; } - $sql = $this->parseSql($this->selectSql, $options); - return $sql; - } - - /** - * 替换SQL语句中表达式 - * @access public - * @param array $options 表达式 - * @return string - */ - public function parseSql($sql, $options = []) - { $sql = str_replace( ['%TABLE%', '%DISTINCT%', '%FIELD%', '%JOIN%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%', '%UNION%', '%LOCK%', '%COMMENT%', '%FORCE%'], [ @@ -512,10 +499,18 @@ abstract class Builder $this->parseLock($options['lock']), $this->parseComment($options['comment']), $this->parseForce($options['force']), - ], $sql); + ], $this->selectSql); return $sql; } + /** + * 生成insert SQL + * @access public + * @param array $data 数据 + * @param array $options 表达式 + * @param bool $replace 是否replace + * @return string + */ public function insert(array $data, $options = [], $replace = false) { // 分析并处理数据 @@ -539,6 +534,13 @@ abstract class Builder return $sql; } + /** + * 生成insertall SQL + * @access public + * @param array $dataSet 数据集 + * @param array $options 表达式 + * @return string + */ public function insertAll($dataSet, $options) { $fields = array_map([$this, 'parseKey'], array_keys($dataSet[0])); @@ -560,6 +562,14 @@ abstract class Builder return $sql; } + /** + * 生成slectinsert SQL + * @access public + * @param array $fields 数据 + * @param string $table 数据表 + * @param array $options 表达式 + * @return string + */ public function selectInsert($fields, $table, $options) { if (is_string($fields)) { @@ -572,9 +582,15 @@ abstract class Builder return $sql; } + /** + * 生成update SQL + * @access public + * @param array $fields 数据 + * @param array $options 表达式 + * @return string + */ public function update($data, $options) { - $table = $this->parseTable($options['table']); $data = $this->parseData($data, $options); if (empty($data)) { @@ -600,6 +616,12 @@ abstract class Builder return $sql; } + /** + * 生成delete SQL + * @access public + * @param array $options 表达式 + * @return string + */ public function delete($options) { $sql = str_replace( diff --git a/library/think/db/Connection.php b/library/think/db/Connection.php index fd4101a2..d7bdc210 100644 --- a/library/think/db/Connection.php +++ b/library/think/db/Connection.php @@ -12,7 +12,6 @@ namespace think\db; use PDO; -use think\Cache; use think\Config; use think\Db; use think\db\Query; @@ -45,8 +44,6 @@ abstract class Connection protected $links = []; // 当前连接ID protected $linkID = null; - // 查询参数 - protected $options = []; // 查询结果类型 protected $fetchType = PDO::FETCH_ASSOC; // 监听回调 @@ -486,207 +483,6 @@ abstract class Connection return $sql; } - /** - * 得到某个字段的值 - * @access public - * @param string $field 字段名 - * @return mixed - */ - public function value($field) - { - // 返回数据个数 - $pdo = $this->field($field)->fetchPdo(true)->find(); - return $pdo->fetchColumn(); - } - - /** - * 得到某个列的数组 - * @access public - * @param string $field 字段名 多个字段用逗号分隔 - * @param string $key 索引 - * @return array - */ - public function column($field, $key = '') - { - $key = $key ? $key . ',' : ''; - $pdo = $this->field($key . $field)->fetchPdo(true)->select(); - if (1 == $pdo->columnCount()) { - return $pdo->fetchAll(PDO::FETCH_COLUMN); - } - $result = $pdo->fetchAll(PDO::FETCH_ASSOC); - $fields = array_keys($result[0]); - $count = count($fields); - $key1 = array_shift($fields); - $key2 = $fields ? array_shift($fields) : ''; - foreach ($result as $val) { - if ($count > 2) { - $array[$val[$key1]] = $val; - } elseif (2 == $count) { - $array[$val[$key1]] = $val[$key2]; - } - } - return $array; - } - - /** - * COUNT查询 - * @access public - * @param string $field 字段名 - * @return integer - */ - public function count($field = '*') - { - return $this->value('COUNT(' . $field . ') AS tp_count'); - } - - /** - * SUM查询 - * @access public - * @param string $field 字段名 - * @return integer - */ - public function sum($field = '*') - { - return $this->value('SUM(' . $field . ') AS tp_sum'); - } - - /** - * MIN查询 - * @access public - * @param string $field 字段名 - * @return integer - */ - public function min($field = '*') - { - return $this->value('MIN(' . $field . ') AS tp_min'); - } - - /** - * MAX查询 - * @access public - * @param string $field 字段名 - * @return integer - */ - public function max($field = '*') - { - return $this->value('MAX(' . $field . ') AS tp_max'); - } - - /** - * AVG查询 - * @access public - * @param string $field 字段名 - * @return integer - */ - public function avg($field = '*') - { - return $this->value('AVG(' . $field . ') AS tp_avg'); - } - - /** - * 设置记录的某个字段值 - * 支持使用数据库字段和方法 - * @access public - * @param string|array $field 字段名 - * @param string $value 字段值 - * @return integer - */ - public function setField($field, $value = '') - { - if (is_array($field)) { - $data = $field; - } else { - $data[$field] = $value; - } - return $this->update($data); - } - - /** - * 字段值(延迟)增长 - * @access public - * @param string $field 字段名 - * @param integer $step 增长值 - * @param integer $lazyTime 延时时间(s) - * @return integer|true - * @throws \think\Exception - */ - public function setInc($field, $step = 1, $lazyTime = 0) - { - $condition = !empty($this->options['where']) ? $this->options['where'] : []; - if (empty($condition)) { - // 没有条件不做任何更新 - throw new Exception('no data to update'); - } - if ($lazyTime > 0) { - // 延迟写入 - $guid = md5($this->name . '_' . $field . '_' . serialize($condition)); - $step = $this->lazyWrite($guid, $step, $lazyTime); - if (empty($step)) { - return true; // 等待下次写入 - } - } - return $this->setField($field, ['exp', $field . '+' . $step]); - } - - /** - * 字段值(延迟)减少 - * @access public - * @param string $field 字段名 - * @param integer $step 减少值 - * @param integer $lazyTime 延时时间(s) - * @return integer|true - * @throws \think\Exception - */ - public function setDec($field, $step = 1, $lazyTime = 0) - { - $condition = !empty($this->options['where']) ? $this->options['where'] : []; - if (empty($condition)) { - // 没有条件不做任何更新 - throw new Exception('no data to update'); - } - if ($lazyTime > 0) { - // 延迟写入 - $guid = md5($this->name . '_' . $field . '_' . serialize($condition)); - $step = $this->lazyWrite($guid, -$step, $lazyTime); - if (empty($step)) { - return true; // 等待下次写入 - } - } - return $this->setField($field, ['exp', $field . '-' . $step]); - } - - /** - * 延时更新检查 返回false表示需要延时 - * 否则返回实际写入的数值 - * @access public - * @param string $guid 写入标识 - * @param integer $step 写入步进值 - * @param integer $lazyTime 延时时间(s) - * @return false|integer - */ - protected function lazyWrite($guid, $step, $lazyTime) - { - if (false !== ($value = Cache::get($guid))) { - // 存在缓存写入数据 - if (NOW_TIME > Cache::get($guid . '_time') + $lazyTime) { - // 延时更新时间到了,删除缓存数据 并实际写入数据库 - Cache::rm($guid); - Cache::rm($guid . '_time'); - return $value + $step; - } else { - // 追加数据到缓存 - Cache::set($guid, $value + $step, 0); - return false; - } - } else { - // 没有缓存数据 - Cache::set($guid, $step, 0); - // 计时开始 - Cache::set($guid . '_time', NOW_TIME, 0); - return false; - } - } - /** * 得到完整的数据表名 * @access public diff --git a/library/think/db/Query.php b/library/think/db/Query.php index 7d8e378d..f25c73ab 100644 --- a/library/think/db/Query.php +++ b/library/think/db/Query.php @@ -12,6 +12,7 @@ namespace think\db; use PDO; +use think\Cache; use think\Config; use think\Db; use think\Exception; @@ -85,6 +86,207 @@ class Query return $builder[$driver]; } + /** + * 得到某个字段的值 + * @access public + * @param string $field 字段名 + * @return mixed + */ + public function value($field) + { + // 返回数据个数 + $pdo = $this->field($field)->fetchPdo(true)->find(); + return $pdo->fetchColumn(); + } + + /** + * 得到某个列的数组 + * @access public + * @param string $field 字段名 多个字段用逗号分隔 + * @param string $key 索引 + * @return array + */ + public function column($field, $key = '') + { + $key = $key ? $key . ',' : ''; + $pdo = $this->field($key . $field)->fetchPdo(true)->select(); + if (1 == $pdo->columnCount()) { + return $pdo->fetchAll(PDO::FETCH_COLUMN); + } + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $fields = array_keys($result[0]); + $count = count($fields); + $key1 = array_shift($fields); + $key2 = $fields ? array_shift($fields) : ''; + foreach ($result as $val) { + if ($count > 2) { + $array[$val[$key1]] = $val; + } elseif (2 == $count) { + $array[$val[$key1]] = $val[$key2]; + } + } + return $array; + } + + /** + * COUNT查询 + * @access public + * @param string $field 字段名 + * @return integer + */ + public function count($field = '*') + { + return $this->value('COUNT(' . $field . ') AS tp_count'); + } + + /** + * SUM查询 + * @access public + * @param string $field 字段名 + * @return integer + */ + public function sum($field = '*') + { + return $this->value('SUM(' . $field . ') AS tp_sum'); + } + + /** + * MIN查询 + * @access public + * @param string $field 字段名 + * @return integer + */ + public function min($field = '*') + { + return $this->value('MIN(' . $field . ') AS tp_min'); + } + + /** + * MAX查询 + * @access public + * @param string $field 字段名 + * @return integer + */ + public function max($field = '*') + { + return $this->value('MAX(' . $field . ') AS tp_max'); + } + + /** + * AVG查询 + * @access public + * @param string $field 字段名 + * @return integer + */ + public function avg($field = '*') + { + return $this->value('AVG(' . $field . ') AS tp_avg'); + } + + /** + * 设置记录的某个字段值 + * 支持使用数据库字段和方法 + * @access public + * @param string|array $field 字段名 + * @param string $value 字段值 + * @return integer + */ + public function setField($field, $value = '') + { + if (is_array($field)) { + $data = $field; + } else { + $data[$field] = $value; + } + return $this->update($data); + } + + /** + * 字段值(延迟)增长 + * @access public + * @param string $field 字段名 + * @param integer $step 增长值 + * @param integer $lazyTime 延时时间(s) + * @return integer|true + * @throws \think\Exception + */ + public function setInc($field, $step = 1, $lazyTime = 0) + { + $condition = !empty($this->options['where']) ? $this->options['where'] : []; + if (empty($condition)) { + // 没有条件不做任何更新 + throw new Exception('no data to update'); + } + if ($lazyTime > 0) { + // 延迟写入 + $guid = md5($this->name . '_' . $field . '_' . serialize($condition)); + $step = $this->lazyWrite($guid, $step, $lazyTime); + if (empty($step)) { + return true; // 等待下次写入 + } + } + return $this->setField($field, ['exp', $field . '+' . $step]); + } + + /** + * 字段值(延迟)减少 + * @access public + * @param string $field 字段名 + * @param integer $step 减少值 + * @param integer $lazyTime 延时时间(s) + * @return integer|true + * @throws \think\Exception + */ + public function setDec($field, $step = 1, $lazyTime = 0) + { + $condition = !empty($this->options['where']) ? $this->options['where'] : []; + if (empty($condition)) { + // 没有条件不做任何更新 + throw new Exception('no data to update'); + } + if ($lazyTime > 0) { + // 延迟写入 + $guid = md5($this->name . '_' . $field . '_' . serialize($condition)); + $step = $this->lazyWrite($guid, -$step, $lazyTime); + if (empty($step)) { + return true; // 等待下次写入 + } + } + return $this->setField($field, ['exp', $field . '-' . $step]); + } + + /** + * 延时更新检查 返回false表示需要延时 + * 否则返回实际写入的数值 + * @access public + * @param string $guid 写入标识 + * @param integer $step 写入步进值 + * @param integer $lazyTime 延时时间(s) + * @return false|integer + */ + protected function lazyWrite($guid, $step, $lazyTime) + { + if (false !== ($value = Cache::get($guid))) { + // 存在缓存写入数据 + if (NOW_TIME > Cache::get($guid . '_time') + $lazyTime) { + // 延时更新时间到了,删除缓存数据 并实际写入数据库 + Cache::rm($guid); + Cache::rm($guid . '_time'); + return $value + $step; + } else { + // 追加数据到缓存 + Cache::set($guid, $value + $step, 0); + return false; + } + } else { + // 没有缓存数据 + Cache::set($guid, $step, 0); + // 计时开始 + Cache::set($guid . '_time', NOW_TIME, 0); + return false; + } + } + /** * 查询SQL组装 join * @access public