diff --git a/library/think/Db.php b/library/think/Db.php index bf67da62..d329b4e8 100644 --- a/library/think/Db.php +++ b/library/think/Db.php @@ -16,6 +16,12 @@ namespace think; */ class Db { + // 数组数据集 + const RESULTSET_ARRAY = 1; + // 对象数据集 + const RESULTSET_COLLECTION = 2; + // 自定义对象数据集 + const RESULTSET_CLASS = 3; // 数据库连接实例 private static $instances = []; // 查询次数 diff --git a/library/think/Paginator.php b/library/think/Paginator.php index 7f046591..ba8aba2e 100644 --- a/library/think/Paginator.php +++ b/library/think/Paginator.php @@ -44,7 +44,7 @@ abstract class Paginator 'fragment' => '' ]; - public function __construct(Collection $items, $listRows, $currentPage = null, $simple = false, $total = null, $options = []) + public function __construct($items, $listRows, $currentPage = null, $simple = false, $total = null, $options = []) { $this->options = array_merge($this->options, $options); @@ -53,17 +53,18 @@ abstract class Paginator $this->simple = $simple; $this->listRows = $listRows; + $this->items = PaginatorCollection::make($items, $this); + if ($simple) { $this->currentPage = $this->setCurrentPage($currentPage); - $this->hasMore = count($items) > ($this->listRows); - $items = $items->slice(0, $this->listRows); + $this->hasMore = count($this->items) > ($this->listRows); + $this->items = $this->items->slice(0, $this->listRows); } else { $this->lastPage = (int)ceil($total / $listRows); $this->currentPage = $this->setCurrentPage($currentPage); $this->hasMore = $this->currentPage < $this->lastPage; } - $this->items = PaginatorCollection::make($items, $this); } public function items() @@ -113,7 +114,7 @@ abstract class Paginator /** * 自动获取当前页码 * @param string $varPage - * @param int $default + * @param int $default * @return int */ public static function getCurrentPage($varPage = 'page', $default = 1) @@ -165,6 +166,7 @@ abstract class Paginator /** * 数据是否足够分页 + * @return boolean */ public function hasPages() { @@ -205,7 +207,7 @@ abstract class Paginator * 添加URL参数 * * @param array|string $key - * @param string|null $value + * @param string|null $value * @return $this */ public function appends($key, $value = null) diff --git a/library/think/db/Connection.php b/library/think/db/Connection.php index 0c5880a0..14ce32bc 100644 --- a/library/think/db/Connection.php +++ b/library/think/db/Connection.php @@ -13,6 +13,7 @@ namespace think\db; use PDO; use PDOStatement; +use think\Collection; use think\Db; use think\Debug; use think\Exception; @@ -52,6 +53,8 @@ abstract class Connection /** @var PDO 当前连接ID */ protected $linkID; + // 查询结果类型 + protected $resultSetType = Db::RESULTSET_ARRAY; // 查询结果类型 protected $fetchType = PDO::FETCH_ASSOC; // 字段属性大小写 @@ -62,37 +65,39 @@ abstract class Connection // 数据库连接参数配置 protected $config = [ // 数据库类型 - 'type' => '', + 'type' => '', // 服务器地址 - 'hostname' => '', + 'hostname' => '', // 数据库名 - 'database' => '', + 'database' => '', // 用户名 - 'username' => '', + 'username' => '', // 密码 - 'password' => '', + 'password' => '', // 端口 - 'hostport' => '', + 'hostport' => '', // 连接dsn - 'dsn' => '', + 'dsn' => '', // 数据库连接参数 - 'params' => [], + 'params' => [], // 数据库编码默认采用utf8 - 'charset' => 'utf8', + 'charset' => 'utf8', // 数据库表前缀 - 'prefix' => '', + 'prefix' => '', // 数据库调试模式 - 'debug' => false, + 'debug' => false, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'deploy' => 0, + 'deploy' => 0, // 数据库读写是否分离 主从式有效 - 'rw_separate' => false, + 'rw_separate' => false, // 读写分离后 主服务器数量 - 'master_num' => 1, + 'master_num' => 1, // 指定从服务器序号 - 'slave_no' => '', + 'slave_no' => '', // 是否严格检查字段是否存在 - 'fields_strict' => true, + 'fields_strict' => true, + // 数据集返回类型 + 'resultset_type' => Db::RESULTSET_ARRAY, ]; // PDO连接参数 @@ -230,7 +235,10 @@ abstract class Connection } // 记录当前字段属性大小写设置 $this->attrCase = $params[PDO::ATTR_CASE]; - + // 记录数据集返回类型 + if (isset($config['resultset_type'])) { + $this->resultSetType = $config['resultset_type']; + } try { if (empty($config['dsn'])) { $config['dsn'] = $this->parseDsn($config); @@ -294,12 +302,12 @@ abstract class Connection * @param array $bind 参数绑定 * @param boolean $fetch 不执行只是获取SQL * @param boolean $master 是否在主服务器读操作 - * @param bool $returnPdo 是否返回 PDOStatement 对象 + * @param bool|string $class 指定返回的数据集对象 * @return mixed * @throws DbBindParamException * @throws PDOException */ - public function query($sql, $bind = [], $fetch = false, $master = false, $returnPdo = false) + public function query($sql, $bind = [], $fetch = false, $master = false, $class = false) { $this->initConnect($master); if (!$this->linkID) { @@ -329,7 +337,7 @@ abstract class Connection $result = $this->PDOStatement->execute(); // 调试结束 $this->debug(false); - return $returnPdo ? $this->PDOStatement : $this->getResult(); + return $this->getResult($class); } catch (\PDOException $e) { throw new PDOException($e, $this->config, $this->queryStr); } @@ -403,8 +411,8 @@ abstract class Connection $val = $this->quote(is_array($val) ? $val[0] : $val); // 判断占位符 $sql = is_numeric($key) ? - substr_replace($sql, $val, strpos($sql, '?'), 1) : - str_replace([':' . $key . ')', ':' . $key . ' '], [$val . ')', $val . ' '], $sql . ' '); + substr_replace($sql, $val, strpos($sql, '?'), 1) : + str_replace([':' . $key . ')', ':' . $key . ' '], [$val . ')', $val . ' '], $sql . ' '); } } return $sql; @@ -443,12 +451,33 @@ abstract class Connection /** * 获得数据集 * @access protected - * @return array + * @param bool|string $class true 返回PDOStatement 字符串用于指定返回的类名 + * @return mixed */ - protected function getResult() + protected function getResult($class = '') { + if (true === $class) { + // 返回PDOStatement对象处理 + return $this->PDOStatement; + } $result = $this->PDOStatement->fetchAll($this->fetchType); $this->numRows = count($result); + + if (!empty($class)) { + // 返回指定数据集对象类 + return new $class($result); + } + switch ($this->resultSetType) { + case Db::RESULTSET_COLLECTION: + // 返回数据集Collection对象 + $result = new Collection($result); + break; + case Db::RESULTSET_CLASS: + break; + case Db::RESULTSET_ARRAY: + default: + // 返回二维数组 + } return $result; } diff --git a/library/think/db/Query.php b/library/think/db/Query.php index 8e2a67cf..71646d7b 100644 --- a/library/think/db/Query.php +++ b/library/think/db/Query.php @@ -847,7 +847,19 @@ class Query */ public function fetchPdo($pdo = true) { - $this->options['fetch_pdo'] = $pdo; + $this->options['fetch_class'] = $pdo; + return $this; + } + + /** + * 指定数据集返回对象 + * @access public + * @param string $class 指定返回的数据集对象类名 + * @return $this + */ + public function fetchClass($class) + { + $this->options['fetch_class'] = $class; return $this; } @@ -1304,7 +1316,7 @@ class Query // 生成查询SQL $sql = $this->builder()->select($options); // 执行查询操作 - $resultSet = $this->connection->query($sql, $this->getBind(), $options['fetch_sql'], $options['master'], $options['fetch_pdo']); + $resultSet = $this->connection->query($sql, $this->getBind(), $options['fetch_sql'], $options['master'], $options['fetch_class']); if (is_string($resultSet)) { // 返回SQL @@ -1322,7 +1334,7 @@ class Query } // 返回结果处理 - if (!empty($resultSet)) { + if ($resultSet) { // 数据列表读取后的处理 if (!empty($options['model'])) { @@ -1340,13 +1352,13 @@ class Query } if (!empty($options['with'])) { // 预载入 - $resultSet = $result->eagerlyResultSet($resultSet, $options['with']); + $resultSet = $result->eagerlyResultSet($resultSet, $options['with'], is_class($resultSet) ? get_class($resultSet) : ''); } } } elseif (!empty($options['fail'])) { throw new DbException('Data not Found', $options, $sql); } - return Collection::make($resultSet); + return $resultSet; } /** @@ -1385,7 +1397,7 @@ class Query // 生成查询SQL $sql = $this->builder()->select($options); // 执行查询 - $result = $this->connection->query($sql, $this->getBind(), $options['fetch_sql'], $options['master'], $options['fetch_pdo']); + $result = $this->connection->query($sql, $this->getBind(), $options['fetch_sql'], $options['master'], $options['fetch_class']); if (is_string($result)) { // 返回SQL @@ -1404,19 +1416,19 @@ class Query } // 数据处理 - if (!empty($result)) { + if (!empty($result[0])) { $data = $result[0]; if (!empty($options['model'])) { // 返回模型对象 $data = new $options['model']($data); - $data->isUpdate(true, $options['where']['AND']); + $data->isUpdate(true, isset($options['where']['AND']) ? $options['where']['AND'] : null); // 关联查询 if (!empty($options['relation'])) { $data->relationQuery($options['relation']); } if (!empty($options['with'])) { // 预载入 - $data->eagerlyResult($data, $options['with']); + $data->eagerlyResult($data, $options['with'], is_object($result) ? get_class($result) : ''); } } } elseif (!empty($options['fail'])) { @@ -1539,7 +1551,7 @@ class Query $options['strict'] = $this->connection->getConfig('fields_strict'); } - foreach (['master', 'lock', 'fetch_pdo', 'fetch_sql', 'distinct'] as $name) { + foreach (['master', 'lock', 'fetch_class', 'fetch_sql', 'distinct'] as $name) { if (!isset($options[$name])) { $options[$name] = false; } diff --git a/library/think/db/connector/Mysql.php b/library/think/db/connector/Mysql.php index 66b16a78..b9d910d3 100644 --- a/library/think/db/connector/Mysql.php +++ b/library/think/db/connector/Mysql.php @@ -11,6 +11,7 @@ namespace think\db\connector; +use PDO; use think\db\Connection; use think\Log; @@ -54,7 +55,8 @@ class Mysql extends Connection $tableName = str_replace('.', '`.`', $tableName); } $sql = 'SHOW COLUMNS FROM `' . $tableName . '`'; - $result = $this->query($sql); + $pdo = $this->linkID->query($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; if ($result) { foreach ($result as $key => $val) { @@ -81,7 +83,8 @@ class Mysql extends Connection public function getTables($dbName = '') { $sql = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES '; - $result = $this->query($sql); + $pdo = $this->linkID->query($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; foreach ($result as $key => $val) { $info[$key] = current($val); @@ -98,7 +101,7 @@ class Mysql extends Connection protected function getExplain($sql) { $pdo = $this->linkID->query("EXPLAIN " . $sql); - $result = $pdo->fetch(\PDO::FETCH_ASSOC); + $result = $pdo->fetch(PDO::FETCH_ASSOC); $result = array_change_key_case($result); if (isset($result['extra'])) { if (strpos($result['extra'], 'filesort') || strpos($result['extra'], 'temporary')) { diff --git a/library/think/db/connector/Oracle.php b/library/think/db/connector/Oracle.php index 87ceaf8b..cc4f6496 100644 --- a/library/think/db/connector/Oracle.php +++ b/library/think/db/connector/Oracle.php @@ -11,6 +11,7 @@ namespace think\db\connector; +use PDO; use think\Db; use think\db\Connection; @@ -102,8 +103,9 @@ class Oracle extends Connection public function getFields($tableName) { list($tableName) = explode(' ', $tableName); - $url = "select a.column_name,data_type,DECODE (nullable, 'Y', 0, 1) notnull,data_default, DECODE (A .column_name,b.column_name,1,0) pk from all_tab_columns a,(select column_name from all_constraints c, all_cons_columns col where c.constraint_name = col.constraint_name and c.constraint_type = 'P' and c.table_name = '" . strtoupper($tableName) . "' ) b where table_name = '" . strtoupper($tableName) . "' and a.column_name = b.column_name (+)"; - $result = $this->query($url); + $sql = "select a.column_name,data_type,DECODE (nullable, 'Y', 0, 1) notnull,data_default, DECODE (A .column_name,b.column_name,1,0) pk from all_tab_columns a,(select column_name from all_constraints c, all_cons_columns col where c.constraint_name = col.constraint_name and c.constraint_type = 'P' and c.table_name = '" . strtoupper($tableName) . "' ) b where table_name = '" . strtoupper($tableName) . "' and a.column_name = b.column_name (+)"; + $pdo = $this->linkID->query($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; if ($result) { foreach ($result as $key => $val) { @@ -129,7 +131,8 @@ class Oracle extends Connection */ public function getTables() { - $result = $this->query("select table_name from all_tables"); + $pdo = $this->linkID->query("select table_name from all_tables"); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; foreach ($result as $key => $val) { $info[$key] = current($val); diff --git a/library/think/db/connector/Pgsql.php b/library/think/db/connector/Pgsql.php index 03406efe..58a33c34 100644 --- a/library/think/db/connector/Pgsql.php +++ b/library/think/db/connector/Pgsql.php @@ -11,6 +11,7 @@ namespace think\db\connector; +use PDO; use think\db\Connection; /** @@ -43,7 +44,9 @@ class Pgsql extends Connection public function getFields($tableName) { list($tableName) = explode(' ', $tableName); - $result = $this->query('select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg(' . $tableName . ');'); + $sql = 'select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg(' . $tableName . ');'; + $pdo = $this->linkID->query($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; if ($result) { foreach ($result as $key => $val) { @@ -69,7 +72,9 @@ class Pgsql extends Connection */ public function getTables($dbName = '') { - $result = $this->query("select tablename as Tables_in_test from pg_tables where schemaname ='public'"); + $sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'"; + $pdo = $this->linkID->query($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; foreach ($result as $key => $val) { $info[$key] = current($val); diff --git a/library/think/db/connector/Sqlite.php b/library/think/db/connector/Sqlite.php index 74ecc40e..e3b03afb 100644 --- a/library/think/db/connector/Sqlite.php +++ b/library/think/db/connector/Sqlite.php @@ -11,6 +11,7 @@ namespace think\db\connector; +use PDO; use think\db\Connection; /** @@ -40,7 +41,9 @@ class Sqlite extends Connection public function getFields($tableName) { list($tableName) = explode(' ', $tableName); - $result = $this->query('PRAGMA table_info( ' . $tableName . ' )'); + $sql = 'PRAGMA table_info( ' . $tableName . ' )'; + $pdo = $this->linkID->query($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; if ($result) { foreach ($result as $key => $val) { @@ -66,10 +69,12 @@ class Sqlite extends Connection */ public function getTables($dbName = '') { - $result = $this->query("SELECT name FROM sqlite_master WHERE type='table' " + $sql = "SELECT name FROM sqlite_master WHERE type='table' " . "UNION ALL SELECT name FROM sqlite_temp_master " - . "WHERE type='table' ORDER BY name"); - $info = []; + . "WHERE type='table' ORDER BY name"; + $pdo = $this->linkID->query($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $info = []; foreach ($result as $key => $val) { $info[$key] = current($val); } diff --git a/library/think/db/connector/Sqlsrv.php b/library/think/db/connector/Sqlsrv.php index 4d42ac1c..2eead773 100644 --- a/library/think/db/connector/Sqlsrv.php +++ b/library/think/db/connector/Sqlsrv.php @@ -51,14 +51,16 @@ class Sqlsrv extends Connection public function getFields($tableName) { list($tableName) = explode(' ', $tableName); - $result = $this->query("SELECT column_name, data_type, column_default, is_nullable + $sql = "SELECT column_name, data_type, column_default, is_nullable FROM information_schema.tables AS t JOIN information_schema.columns AS c ON t.table_catalog = c.table_catalog AND t.table_schema = c.table_schema AND t.table_name = c.table_name - WHERE t.table_name = '$tableName'"); - $info = []; + WHERE t.table_name = '$tableName'"; + $pdo = $this->linkID->query($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $info = []; if ($result) { foreach ($result as $key => $val) { $val = array_change_key_case($val); @@ -83,11 +85,13 @@ class Sqlsrv extends Connection */ public function getTables($dbName = '') { - $result = $this->query("SELECT TABLE_NAME + $sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' - "); - $info = []; + "; + $pdo = $this->linkID->query($sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $info = []; foreach ($result as $key => $val) { $info[$key] = current($val); } diff --git a/library/think/model/Relation.php b/library/think/model/Relation.php index 22223dd2..654a7b9b 100644 --- a/library/think/model/Relation.php +++ b/library/think/model/Relation.php @@ -11,7 +11,6 @@ namespace think\model; -use think\Collection; use think\Db; use think\Exception; use think\Loader; @@ -115,9 +114,10 @@ class Relation * @access public * @param array $resultSet 数据集 * @param string $relation 关联名 + * @param string $class 数据集对象名 为空表示数组 * @return array */ - public function eagerlyResultSet($resultSet, $relation) + public function eagerlyResultSet($resultSet, $relation, $class = '') { /** @var array $relations */ $relations = is_string($relation) ? explode(',', $relation) : $relation; @@ -167,7 +167,7 @@ class Relation if (!isset($data[$result->$localKey])) { $data[$result->$localKey] = []; } - $result->__set($relation, Collection::make($data[$result->$localKey])); + $result->__set($relation, $this->resultSetBuild($data[$result->$localKey], $class)); } } break; @@ -196,7 +196,7 @@ class Relation $data[$result->$pk] = []; } - $result->__set($relation, Collection::make($data[$result->$pk])); + $result->__set($relation, $this->resultSetBuild($data[$result->$pk], $class)); } } break; @@ -205,14 +205,27 @@ class Relation return $resultSet; } + /** + * 封装关联数据集 + * @access public + * @param array $resultSet 数据集 + * @param string $class 数据集类名 + * @return mixed + */ + protected function resultSetBuild($resultSet, $class = '') + { + return $class ? new $class($resultSet) : $resultSet; + } + /** * 预载入关联查询 返回模型对象 * @access public * @param Model $result 数据对象 * @param string $relation 关联名 + * @param string $class 数据集对象名 为空表示数组 * @return \think\Model */ - public function eagerlyResult($result, $relation) + public function eagerlyResult($result, $relation, $class = '') { $relations = is_string($relation) ? explode(',', $relation) : $relation; @@ -243,7 +256,7 @@ class Relation if (!isset($data[$result->$localKey])) { $data[$result->$localKey] = []; } - $result->__set($relation, Collection::make($data[$result->$localKey])); + $result->__set($relation, $this->resultSetBuild($data[$result->$localKey], $class)); } break; case self::BELONGS_TO_MANY: @@ -257,7 +270,7 @@ class Relation if (!isset($data[$pk])) { $data[$pk] = []; } - $result->__set($relation, Collection::make($data[$pk])); + $result->__set($relation, $this->resultSetBuild($data[$pk], $class)); } break;