提交的内容

This commit is contained in:
2025-05-12 15:45:02 +08:00
parent 629c4750da
commit b48c692775
3043 changed files with 34732 additions and 60810 deletions

32
vendor/topthink/think-orm/src/db/BaseBuilder.php vendored Executable file → Normal file
View File

@ -9,13 +9,15 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db;
use BackedEnum;
use Closure;
use think\db\BaseQuery as Query;
use think\db\exception\DbException as Exception;
use UnitEnum;
/**
* Db Base Builder.
@ -94,7 +96,7 @@ abstract class BaseBuilder
*
* @param ConnectionInterface $connection 数据库连接对象实例
*/
public function __construct(ConnectionInterface $connection)
public function __construct(?ConnectionInterface $connection)
{
$this->connection = $connection;
}
@ -157,7 +159,7 @@ abstract class BaseBuilder
*
* @return string
*/
abstract public function parseKey(Query $query, string|int|Raw $key, bool $strict = false): string;
abstract public function parseKey(Query $query, string | int | Raw $key, bool $strict = false): string;
/**
* 查询额外参数分析.
@ -187,7 +189,7 @@ abstract class BaseBuilder
*
* @return string
*/
abstract protected function parseTable(Query $query, array|string $tables): string;
abstract protected function parseTable(Query $query, array | string $tables): string;
/**
* where分析.
@ -273,7 +275,7 @@ abstract class BaseBuilder
$where[] = $this->parseFieldsAnd($query, $value, $field, $logic, $binds);
} else {
// 对字段使用表达式查询
$field = is_string($field) ? $field : '';
$field = is_string($field) ? $field : '';
$where[] = ' ' . $logic . ' ' . $this->parseWhereItem($query, $field, $value, $binds);
}
}
@ -466,7 +468,7 @@ abstract class BaseBuilder
*
* @return string
*/
abstract protected function parseBetween(Query $query, string $key, string $exp, array|string $value, $field, int $bindType): string;
abstract protected function parseBetween(Query $query, string $key, string $exp, array | string $value, $field, int $bindType): string;
/**
* Exists查询.
@ -480,7 +482,7 @@ abstract class BaseBuilder
*
* @return string
*/
protected function parseExists(Query $query, string $key, string $exp, Raw|Closure $value, string $field, int $bindType): string
protected function parseExists(Query $query, string $key, string $exp, Raw | Closure $value, string $field, int $bindType): string
{
// EXISTS 查询
if ($value instanceof Closure) {
@ -532,6 +534,10 @@ abstract class BaseBuilder
$value = $this->parseClosure($query, $value);
} elseif ($value instanceof Raw) {
$value = $this->parseRaw($query, $value);
} elseif ($value instanceof BackedEnum) {
$value = $value->value;
} elseif ($value instanceof UnitEnum) {
$value = $value->name;
}
if ('=' == $exp && is_null($value)) {
@ -560,9 +566,9 @@ abstract class BaseBuilder
}
return $key . ' ' . substr($exp, 0, -4)
. $this->parseDateTime($query, $value[0], $field, $bindType)
. ' AND '
. $this->parseDateTime($query, $value[1], $field, $bindType);
. $this->parseDateTime($query, $value[0], $field, $bindType)
. ' AND '
. $this->parseDateTime($query, $value[1], $field, $bindType);
}
/**
@ -665,7 +671,7 @@ abstract class BaseBuilder
*
* @return string
*/
abstract protected function parseGroup(Query $query, string|array $group): string;
abstract protected function parseGroup(Query $query, string | array $group): string;
/**
* having分析.
@ -740,7 +746,7 @@ abstract class BaseBuilder
*
* @return string
*/
abstract protected function parseForce(Query $query, string|array $index): string;
abstract protected function parseForce(Query $query, string | array $index): string;
/**
* 设置锁机制.
@ -750,7 +756,7 @@ abstract class BaseBuilder
*
* @return string
*/
abstract protected function parseLock(Query $query, bool|string $lock = false): string;
abstract protected function parseLock(Query $query, bool | string $lock = false): string;
/**
* 生成查询SQL.

331
vendor/topthink/think-orm/src/db/BaseQuery.php vendored Executable file → Normal file
View File

@ -9,7 +9,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db;
@ -70,6 +70,13 @@ abstract class BaseQuery
*/
protected $prefix = '';
/**
* 当前数据表后缀
*
* @var string
*/
protected $suffix = '';
/**
* 当前查询参数.
*
@ -84,8 +91,8 @@ abstract class BaseQuery
*/
public function __construct(ConnectionInterface $connection)
{
$this->connection = $connection;
$this->prefix = $this->connection->getConfig('prefix');
$this->connection = $connection;
$this->prefix = $this->connection->getConfig('prefix');
}
/**
@ -130,10 +137,8 @@ abstract class BaseQuery
if ($this->model && method_exists($this->model, 'scope' . $method)) {
// 动态调用命名范围
$method = 'scope' . $method;
array_unshift($args, $this);
call_user_func_array([$this->model, $method], $args);
$this->options['scope'][$method] = [[$this->model, 'scope' . $method], $args];
return $this;
}
@ -157,7 +162,7 @@ abstract class BaseQuery
if (isset($this->options['table'])) {
$query->table($this->options['table']);
} else {
$query->name($this->name);
$query->name($this->name)->suffix($this->suffix);
}
if (!empty($this->options['json'])) {
@ -172,6 +177,10 @@ abstract class BaseQuery
$query->lazyFields($this->options['lazy_fields']);
}
if (isset($this->options['alias'])) {
$query->alias($this->options['alias']);
}
return $query;
}
@ -199,6 +208,20 @@ abstract class BaseQuery
return $this;
}
/**
* 指定当前数据表后缀.
*
* @param string $suffix 后缀
*
* @return $this
*/
public function suffix(string $suffix)
{
$this->suffix = $suffix;
return $this;
}
/**
* 获取当前的数据表名称.
*
@ -258,20 +281,21 @@ abstract class BaseQuery
/**
* 得到当前或者指定名称的数据表.
* @param bool $alias 是否返回数据表别名
*
* @param string $name 不含前缀的数据表名字
*
* @return mixed
* @return string|array|Raw
*/
public function getTable(string $name = '')
public function getTable(bool $alias = false)
{
if (empty($name) && isset($this->options['table'])) {
return $this->options['table'];
if (isset($this->options['table'])) {
$table = $this->options['table'];
if ($alias && is_string($table) && !empty($this->options['alias'][$table])) {
return $this->options['alias'][$table];
}
return $table;
}
$name = $name ?: $this->name;
return $this->prefix . Str::snake($name);
return $this->prefix . Str::snake($this->name) . $this->suffix;
}
/**
@ -288,6 +312,20 @@ abstract class BaseQuery
return $this;
}
/**
* 设置只读字段.
*
* @param array $fields 只读字段
*
* @return $this
*/
public function readonly(array $fields)
{
$this->options['readonly_fields'] = $fields;
return $this;
}
/**
* 获取最近一次查询的sql语句.
*
@ -311,11 +349,11 @@ abstract class BaseQuery
/**
* 获取最近插入的ID.
*
* @param string $sequence 自增序列名
* @param string|null $sequence 自增序列名
*
* @return mixed
*/
public function getLastInsID(string $sequence = null)
public function getLastInsID(?string $sequence = null)
{
return $this->connection->getLastInsID($this, $sequence);
}
@ -325,36 +363,98 @@ abstract class BaseQuery
*
* @param string $field 字段名
* @param mixed $default 默认值
* @param bool $useModelAttr 是否使用模型获取器
*
* @return mixed
*/
public function value(string $field, $default = null)
public function value(string $field, $default = null, bool $useModelAttr = false)
{
$result = $this->connection->value($this, $field, $default);
$array[$field] = $result;
$this->result($array);
if ($this->model && $useModelAttr) {
// JSON数据处理
if (!empty($this->options['json'])) {
$this->jsonModelResult($array);
}
return $this->model->newInstance($array)->getAttr($field);
}
if (!empty($this->options['json'])) {
$this->jsonResult($array);
}
return $array[$field];
}
/**
* 得到某个字段的值 并且经过模型的获取器处理
*
* @param string $field 字段名
* @param mixed $default 默认值
*
* @return mixed
*/
public function valueWithAttr(string $field, $default = null)
{
return $this->value($field, $default, true);
}
/**
* 得到某个列的数组.
*
* @param string|array $field 字段名 多个字段用逗号分隔
* @param string $key 索引
* @param bool $useModelAttr 是否使用模型获取器
*
* @return array
*/
public function column(string|array $field, string $key = ''): array
public function column(string | array $field, string $key = '', bool $useModelAttr = false): array
{
$result = $this->connection->column($this, $field, $key);
return array_map(function ($item) use ($field, $useModelAttr) {
if (is_array($item)) {
if ($this->model && $useModelAttr) {
// JSON数据处理
if (!empty($this->options['json'])) {
$this->jsonModelResult($item);
}
return $this->model->newInstance($item)->toArray();
}
if (!empty($this->options['json'])) {
$this->jsonResult($item);
}
return $item;
}
if (count($result) != count($result, 1)) {
$this->resultSet($result, false);
}
if (is_array($field) && 1 === count($field)) {
$field = current($field);
}
return $result;
$array[$field] = $item;
if ($this->model && $useModelAttr) {
if (!empty($this->options['json'])) {
$this->jsonModelResult($array);
}
return $this->model->newInstance($array)->getAttr($field);
}
if (!empty($this->options['json'])) {
$this->jsonResult($array);
}
return $array[$field];
}, $result);
}
/**
* 得到某个列的数组 并且经过模型的获取器处理.
*
* @param string|array $field 字段名 多个字段用逗号分隔
* @param string $key 索引
*
* @return array
*/
public function columnWithAttr(string | array $field, string $key = '')
{
return $this->column($field, $key, true);
}
/**
@ -365,7 +465,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function union(string|array|Closure $union, bool $all = false)
public function union(string | array | Closure $union, bool $all = false)
{
$this->options['union']['type'] = $all ? 'UNION ALL' : 'UNION';
@ -385,7 +485,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function unionAll(string|array|Closure $union)
public function unionAll(string | array | Closure $union)
{
return $this->union($union, true);
}
@ -397,7 +497,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function field(string|array|Raw|bool $field)
public function field(string | array | Raw | bool $field)
{
if (empty($field)) {
return $this;
@ -437,7 +537,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function withoutField(array|string $field)
public function withoutField(array | string $field)
{
if (empty($field)) {
return $this;
@ -470,7 +570,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function tableField(string|array|bool $field, string $tableName, string $prefix = '', string $alias = '')
public function tableField(string | array | bool $field, string $tableName, string $prefix = '', string $alias = '')
{
if (empty($field)) {
return $this;
@ -530,8 +630,8 @@ abstract class BaseQuery
public function removeOption(string $option = '')
{
if ('' === $option) {
$this->options = [];
$this->bind = [];
$this->options = [];
$this->bind = [];
} elseif (isset($this->options[$option])) {
unset($this->options[$option]);
}
@ -542,12 +642,12 @@ abstract class BaseQuery
/**
* 指定查询数量.
*
* @param int $offset 起始位置
* @param int $length 查询数量
* @param int $offset 起始位置
* @param int|null $length 查询数量
*
* @return $this
*/
public function limit(int $offset, int $length = null)
public function limit(int $offset, ?int $length = null)
{
$this->options['limit'] = $offset . ($length ? ',' . $length : '');
@ -557,12 +657,12 @@ abstract class BaseQuery
/**
* 指定分页.
*
* @param int $page 页数
* @param int $listRows 每页数量
* @param int $page 页数
* @param int|null $listRows 每页数量
*
* @return $this
*/
public function page(int $page, int $listRows = null)
public function page(int $page, ?int $listRows = null)
{
$this->options['page'] = [$page, $listRows];
@ -576,7 +676,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function table(string|array|Raw $table)
public function table(string | array | Raw $table)
{
if (is_string($table) && !str_contains($table, ')')) {
$table = $this->tableStr($table);
@ -595,20 +695,20 @@ abstract class BaseQuery
*
* @return array|string
*/
protected function tableStr(string $table): array|string
protected function tableStr(string $table): array | string
{
if (!str_contains($table, ',')) {
// 单表
if (str_contains($table, ' ')) {
[$item, $alias] = explode(' ', $table);
$table = [];
$table = [];
$this->alias([$item => $alias]);
$table[$item] = $alias;
}
} else {
// 多表
$tables = explode(',', $table);
$table = [];
$table = [];
foreach ($tables as $item) {
$item = trim($item);
@ -654,7 +754,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function order(string|array|Raw $field, string $order = '')
public function order(string | array | Raw $field, string $order = '')
{
if (empty($field)) {
return $this;
@ -700,14 +800,14 @@ abstract class BaseQuery
/**
* 分页查询.
*
* @param int|array $listRows 每页数量 数组表示配置参数
* @param int|bool $simple 是否简洁模式或者总记录数
*
* @throws Exception
* @param int|array|null $listRows 每页数量 数组表示配置参数
* @param int|bool $simple 是否简洁模式或者总记录数
*
* @return Paginator
*
* @throws Exception
*/
public function paginate(int|array $listRows = null, int|bool $simple = false): Paginator
public function paginate(int | array | null $listRows = null, int | bool $simple = false): Paginator
{
if (is_int($simple)) {
$total = $simple;
@ -715,18 +815,18 @@ abstract class BaseQuery
}
$defaultConfig = [
'query' => [], //url额外参数
'fragment' => '', //url锚点
'var_page' => 'page', //分页变量
'query' => [], //url额外参数
'fragment' => '', //url锚点
'var_page' => 'page', //分页变量
'list_rows' => 15, //每页数量
];
if (is_array($listRows)) {
$config = array_merge($defaultConfig, $listRows);
$listRows = intval($config['list_rows']);
$config = array_merge($defaultConfig, $listRows);
$listRows = intval($config['list_rows']);
} else {
$config = $defaultConfig;
$listRows = intval($listRows ?: $config['list_rows']);
$config = $defaultConfig;
$listRows = intval($listRows ?: $config['list_rows']);
}
$page = isset($config['page']) ? (int) $config['page'] : Paginator::getCurrentPage($config['var_page']);
@ -738,8 +838,8 @@ abstract class BaseQuery
unset($this->options['order'], $this->options['cache'], $this->options['limit'], $this->options['page'], $this->options['field']);
$bind = $this->bind;
$total = $this->count();
$bind = $this->bind;
$total = $this->count();
if ($total > 0) {
$results = $this->options($options)->bind($bind)->page($page, $listRows)->select();
} else {
@ -750,10 +850,10 @@ abstract class BaseQuery
}
}
} elseif ($simple) {
$results = $this->limit(($page - 1) * $listRows, $listRows + 1)->select();
$total = null;
$results = $this->limit(($page - 1) * $listRows, $listRows + 1)->select();
$total = null;
} else {
$results = $this->page($page, $listRows)->select();
$results = $this->page($page, $listRows)->select();
}
$this->removeOption('limit');
@ -765,32 +865,32 @@ abstract class BaseQuery
/**
* 根据数字类型字段进行分页查询(大数据).
*
* @param int|array $listRows 每页数量或者分页配置
* @param string $key 分页索引键
* @param string $sort 索引键排序 asc|desc
*
* @throws Exception
* @param int|array|null $listRows 每页数量或者分页配置
* @param string|null $key 分页索引键
* @param string|null $sort 索引键排序 asc|desc
*
* @return Paginator
*
* @throws Exception
*/
public function paginateX(int|array $listRows = null, string $key = null, string $sort = null): Paginator
public function paginateX(int | array | null $listRows = null, ?string $key = null, ?string $sort = null): Paginator
{
$defaultConfig = [
'query' => [], //url额外参数
'fragment' => '', //url锚点
'var_page' => 'page', //分页变量
'query' => [], //url额外参数
'fragment' => '', //url锚点
'var_page' => 'page', //分页变量
'list_rows' => 15, //每页数量
];
$config = is_array($listRows) ? array_merge($defaultConfig, $listRows) : $defaultConfig;
$listRows = is_int($listRows) ? $listRows : (int) $config['list_rows'];
$page = isset($config['page']) ? (int) $config['page'] : Paginator::getCurrentPage($config['var_page']);
$page = max($page, 1);
$config = is_array($listRows) ? array_merge($defaultConfig, $listRows) : $defaultConfig;
$listRows = is_int($listRows) ? $listRows : (int) $config['list_rows'];
$page = isset($config['page']) ? (int) $config['page'] : Paginator::getCurrentPage($config['var_page']);
$page = max($page, 1);
$config['path'] = $config['path'] ?? Paginator::getCurrentPath();
$key = $key ?: $this->getPk();
$options = $this->getOptions();
$key = $key ?: $this->getPk();
$options = $this->getOptions();
if (is_null($sort)) {
$order = $options['order'] ?? '';
@ -837,16 +937,16 @@ abstract class BaseQuery
/**
* 根据最后ID查询更多N个数据.
*
* @param int $limit LIMIT
* @param int|string $lastId LastId
* @param string $key 分页索引键 默认为主键
* @param string $sort 索引键排序 asc|desc
*
* @throws Exception
* @param int $limit 数量
* @param int|string|null $lastId 最后ID
* @param string|null $key 分页索引键 默认为主键
* @param string|null $sort 索引键排序 asc|desc
*
* @return array
*
* @throws Exception
*/
public function more(int $limit, int|string $lastId = null, string $key = null, string $sort = null): array
public function more(int $limit, int | string | null $lastId = null, ?string $key = null, ?string $sort = null): array
{
$key = $key ?: $this->getPk();
@ -901,12 +1001,12 @@ abstract class BaseQuery
return $this;
}
if ($key instanceof \DateTimeInterface || $key instanceof \DateInterval || (is_int($key) && is_null($expire))) {
if ($key instanceof \DateTimeInterface || $key instanceof \DateInterval || (is_int($key) && is_null($expire))) {
$expire = $key;
$key = true;
}
$this->options['cache'] = [$key, $expire, $tag ?: $this->getTable()];
$this->options['cache'] = [$key, $expire, $tag ?: var_export($this->getTable(), true)];
return $this;
}
@ -921,7 +1021,7 @@ abstract class BaseQuery
*/
public function cacheAlways($key = true, $expire = null, $tag = null)
{
$this->options['cache_always'] = true;
$this->options['cache_always'] = true;
return $this->cache($key, $expire, $tag);
}
@ -936,7 +1036,7 @@ abstract class BaseQuery
*/
public function cacheForce($key = true, $expire = null, $tag = null)
{
$this->options['force_cache'] = true;
$this->options['force_cache'] = true;
return $this->cache($key, $expire, $tag);
}
@ -948,7 +1048,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function lock(bool|string $lock = false)
public function lock(bool | string $lock = false)
{
$this->options['lock'] = $lock;
@ -966,7 +1066,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function alias(array|string $alias)
public function alias(array | string $alias)
{
if (is_array($alias)) {
$this->options['alias'] = $alias;
@ -1010,11 +1110,11 @@ abstract class BaseQuery
/**
* 设置自增序列名.
*
* @param string $sequence 自增序列名
* @param string|null $sequence 自增序列名
*
* @return $this
*/
public function sequence(string $sequence = null)
public function sequence(?string $sequence = null)
{
$this->options['sequence'] = $sequence;
@ -1031,8 +1131,8 @@ abstract class BaseQuery
*/
public function json(array $json = [], bool $assoc = false)
{
$this->options['json'] = $json;
$this->options['json_assoc'] = $assoc;
$this->options['json'] = $json;
$this->options['json_assoc'] = $assoc;
return $this;
}
@ -1058,7 +1158,7 @@ abstract class BaseQuery
*
* @return $this
*/
public function pk(string|array|bool $pk)
public function pk(string | array | bool $pk)
{
$this->pk = $pk;
@ -1252,11 +1352,20 @@ abstract class BaseQuery
$this->where($this->model->getWhere());
}
if (empty($this->options['where'])) {
if (empty($this->options['where']) && empty($this->options['scope'])) {
// 如果没有任何更新条件则不执行
throw new Exception('miss update condition');
}
// 检查只读字段
if (!empty($this->options['readonly_fields'])) {
foreach ($this->options['readonly_fields'] as $field) {
if (array_key_exists($field, $this->options['data'])) {
unset($this->options['data'][$field]);
}
}
}
return $this->connection->update($this);
}
@ -1280,7 +1389,7 @@ abstract class BaseQuery
$this->where($this->model->getWhere());
}
if (true !== $data && empty($this->options['where'])) {
if (true !== $data && empty($this->options['where']) && empty($this->options['scope'])) {
// 如果条件为空 不进行删除操作 除非设置 1=1
throw new Exception('delete without condition');
}
@ -1306,11 +1415,7 @@ abstract class BaseQuery
*
* @param array $data 主键数据
*
* @throws Exception
* @throws ModelNotFoundException
* @throws DataNotFoundException
*
* @return Collection|array|static[]
* @return \think\model\Collection|\think\Collection
*/
public function select(array $data = []): Collection
{
@ -1340,22 +1445,25 @@ abstract class BaseQuery
/**
* 查找单条记录.
*
* @param mixed $data 主键数据
* @param mixed $data 主键数据
* @param ?Closure $closure 闭包数据
*
* @throws Exception
* @throws ModelNotFoundException
* @throws DataNotFoundException
*
* @return mixed
* @return static|\think\Model|array|null
*/
public function find($data = null)
public function find($data = null, ?Closure $closure = null)
{
if (!is_null($data)) {
if ($data instanceof Closure) {
$closure = $data;
} elseif (!is_null($data)) {
// AR模式分析主键条件
$this->parsePkWhere($data);
}
if (empty($this->options['where']) && empty($this->options['order'])) {
if (empty($this->options['where']) && empty($this->options['scope']) && empty($this->options['order']) && empty($this->options['sort'])) {
$result = [];
} else {
$result = $this->connection->find($this);
@ -1363,7 +1471,7 @@ abstract class BaseQuery
// 数据处理
if (empty($result)) {
return $this->resultToEmpty();
return $this->resultToEmpty($closure);
}
if (!empty($this->model)) {
@ -1383,6 +1491,9 @@ abstract class BaseQuery
*/
public function parseOptions(): array
{
// 执行全局查询范围
$this->scopeQuery();
$options = $this->getOptions();
// 获取数据表
@ -1423,9 +1534,9 @@ abstract class BaseQuery
// 根据页数计算limit
[$page, $listRows] = $options['page'];
$page = $page > 0 ? $page : 1;
$listRows = $listRows ?: (is_numeric($options['limit']) ? $options['limit'] : 20);
$offset = $listRows * ($page - 1);
$page = $page > 0 ? $page : 1;
$listRows = $listRows ?: (is_numeric($options['limit']) ? $options['limit'] : 20);
$offset = $listRows * ($page - 1);
$options['limit'] = $offset . ',' . $listRows;
}
@ -1446,7 +1557,7 @@ abstract class BaseQuery
*/
public function parseUpdateData(array &$data): bool
{
$pk = $this->getPk();
$pk = $this->getPk();
$isUpdate = false;
// 如果存在主键数据 则自动作为更新条件
if (is_string($pk) && isset($data[$pk])) {

95
vendor/topthink/think-orm/src/db/Builder.php vendored Executable file → Normal file
View File

@ -9,14 +9,16 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db;
use BackedEnum;
use Closure;
use Stringable;
use think\db\BaseQuery as Query;
use think\db\exception\DbException as Exception;
use UnitEnum;
/**
* Db Builder.
@ -59,30 +61,34 @@ class Builder extends BaseBuilder
foreach ($data as $key => $val) {
$item = $this->parseKey($query, $key, true);
if ($val instanceof Raw) {
if ($val instanceof BackedEnum) {
$val = $val->value;
} elseif ($val instanceof UnitEnum) {
$val = $val->name;
} elseif ($val instanceof Raw) {
$result[$item] = $this->parseRaw($query, $val);
continue;
} elseif (is_null($val) && in_array($key, $fields, true)) {
$result[$item] = 'NULL';
continue;
} elseif (!is_scalar($val) && (in_array($key, (array) $query->getOptions('json')) || 'json' == $query->getFieldType($key))) {
$val = json_encode($val);
}
if (str_contains($key, '->')) {
[$key, $name] = explode('->', $key, 2);
$item = $this->parseKey($query, $key);
$item = $this->parseKey($query, $key);
$result[$item . '->' . $name] = 'json_set(' . $item . ', \'$.' . $name . '\', ' . $this->parseDataBind($query, $key . '->' . $name, $val, $bind) . ')';
} elseif (!str_contains($key, '.') && !in_array($key, $fields, true)) {
if ($options['strict']) {
throw new Exception('fields not exists:[' . $key . ']');
}
} elseif (is_null($val)) {
$result[$item] = 'NULL';
} elseif (is_array($val) && !empty($val) && is_string($val[0])) {
if (in_array(strtoupper($val[0]), ['INC', 'DEC'])) {
$result[$item] = match (strtoupper($val[0])) {
'INC' => $item . ' + ' . floatval($val[1]),
'DEC' => $item . ' - ' . floatval($val[1]),
$result[$item] = match (strtoupper($val[0])) {
'INC' => $item . ' + ' . floatval($val[1]),
'DEC' => $item . ' - ' . floatval($val[1]),
};
}
} elseif (is_scalar($val)) {
@ -127,7 +133,7 @@ class Builder extends BaseBuilder
*
* @return string
*/
public function parseKey(Query $query, string|int|Raw $key, bool $strict = false): string
public function parseKey(Query $query, string | int | Raw $key, bool $strict = false): string
{
return $key;
}
@ -155,26 +161,23 @@ class Builder extends BaseBuilder
*/
protected function parseField(Query $query, array $fields): string
{
if (!empty($fields)) {
// 支持 'field1'=>'field2' 这样的字段别名定义
$array = [];
foreach ($fields as $key => $field) {
if ($field instanceof Raw) {
$array[] = $this->parseRaw($query, $field);
} elseif (!is_numeric($key)) {
$array[] = $this->parseKey($query, $key) . ' AS ' . $this->parseKey($query, $field, true);
} else {
$array[] = $this->parseKey($query, $field);
}
}
$fieldsStr = implode(',', $array);
} else {
$fieldsStr = '*';
if (empty($fields)) {
return '*';
}
return $fieldsStr;
// 支持 'field1' => 'field2' 这样的字段别名定义
$array = array_map(function ($field, $key) use ($query) {
if ($field instanceof Raw) {
return $this->parseRaw($query, $field);
} elseif (!is_numeric($key)) {
// 字段别名定义
return $this->parseKey($query, $key) . ' AS ' . $this->parseKey($query, $field, true);
} else {
return $this->parseKey($query, $field);
}
}, $fields, array_keys($fields));
return implode(',', $array);
}
/**
@ -185,9 +188,9 @@ class Builder extends BaseBuilder
*
* @return string
*/
protected function parseTable(Query $query, array|string $tables): string
protected function parseTable(Query $query, array | string $tables): string
{
$item = [];
$item = [];
$options = $query->getOptions();
foreach ((array) $tables as $key => $table) {
@ -215,14 +218,14 @@ class Builder extends BaseBuilder
*/
protected function parseWhere(Query $query, array $where): string
{
$options = $query->getOptions();
$options = $query->getOptions();
$whereStr = $this->buildWhere($query, $where);
if (!empty($options['soft_delete'])) {
// 附加软删除条件
[$field, $condition] = $options['soft_delete'];
$binds = $query->getFieldsBindType();
$binds = $query->getFieldsBindType();
$whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : '';
$whereStr = $whereStr . $this->parseWhereItem($query, $field, $condition, $binds);
}
@ -267,12 +270,16 @@ class Builder extends BaseBuilder
} elseif ($value instanceof Stringable) {
// 对象数据写入
$value = $value->__toString();
} elseif ($value instanceof BackedEnum) {
$value = $value->value;
} elseif ($value instanceof UnitEnum) {
$value = $value->name;
}
if (is_scalar($value) && !in_array($exp, ['EXP', 'NOT NULL', 'NULL', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN']) && !str_contains($exp, 'TIME')) {
if (is_string($value) && str_starts_with($value, ':') && $query->isBind(substr($value, 1))) {
} else {
$name = $query->bindValue($value, $bindType);
$name = $query->bindValue($value, $bindType);
$value = ':' . $name;
}
}
@ -306,7 +313,7 @@ class Builder extends BaseBuilder
if (is_array($value)) {
$array = [];
foreach ($value as $item) {
$name = $query->bindValue($item, Connection::PARAM_STR);
$name = $query->bindValue($item, Connection::PARAM_STR);
$array[] = $key . ' ' . $exp . ' :' . $name;
}
@ -366,7 +373,7 @@ class Builder extends BaseBuilder
*
* @return string
*/
protected function parseBetween(Query $query, string $key, string $exp, array|string $value, $field, int $bindType): string
protected function parseBetween(Query $query, string $key, string $exp, array | string $value, $field, int $bindType): string
{
// BETWEEN 查询
$data = is_array($value) ? $value : explode(',', $value);
@ -405,8 +412,8 @@ class Builder extends BaseBuilder
if ($query->isAutoBind()) {
$array = [];
foreach ($value as $v) {
$name = $query->bindValue($v, $bindType);
$array[] = ':' . $name;
$name = $query->bindValue($v, $bindType);
$array[] = ':' . $name;
}
$value = implode(',', $array);
} elseif (Connection::PARAM_STR == $bindType) {
@ -541,8 +548,8 @@ class Builder extends BaseBuilder
}
if (preg_match('/^[\w\.]+$/', $key)) {
$sort = strtoupper($sort);
$sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
$sort = strtoupper($sort);
$sort = in_array($sort, ['ASC', 'DESC'], true) ? ' ' . $sort : '';
$array[] = $this->parseKey($query, $key, true) . $sort;
} else {
throw new Exception('order express error:' . $key);
@ -563,8 +570,8 @@ class Builder extends BaseBuilder
*/
protected function parseRaw(Query $query, Raw $raw): string
{
$sql = $raw->getValue();
$bind = $raw->getBind();
$sql = $raw->getValue();
$bind = $raw->getBind();
if ($bind) {
$query->bindParams($sql, $bind);
@ -622,7 +629,7 @@ class Builder extends BaseBuilder
*
* @return string
*/
protected function parseGroup(Query $query, string|array $group): string
protected function parseGroup(Query $query, string | array $group): string
{
if (empty($group)) {
return '';
@ -691,7 +698,7 @@ class Builder extends BaseBuilder
*
* @return string
*/
protected function parseForce(Query $query, string|array $index): string
protected function parseForce(Query $query, string | array $index): string
{
if (empty($index)) {
return '';
@ -712,7 +719,7 @@ class Builder extends BaseBuilder
*
* @return string
*/
protected function parseLock(Query $query, bool|string $lock = false): string
protected function parseLock(Query $query, bool | string $lock = false): string
{
if (is_bool($lock)) {
return $lock ? ' FOR UPDATE ' : '';

2
vendor/topthink/think-orm/src/db/CacheItem.php vendored Executable file → Normal file
View File

@ -58,7 +58,7 @@ class CacheItem
*/
protected $isHit = false;
public function __construct(string $key = null)
public function __construct(?string $key = null)
{
$this->key = $key;
}

15
vendor/topthink/think-orm/src/db/Connection.php vendored Executable file → Normal file
View File

@ -9,7 +9,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db;
@ -282,7 +282,7 @@ abstract class Connection implements ConnectionInterface
}
$runtime = number_format((microtime(true) - $this->queryStartTime), 6);
$sql = $sql ?: $this->getLastsql();
$sql = $sql ?: $this->getLastsql();
if (empty($this->config['deploy'])) {
$master = null;
@ -320,7 +320,7 @@ abstract class Connection implements ConnectionInterface
protected function getCacheKey(BaseQuery $query, string $method = ''): string
{
if (!empty($query->getOptions('key')) && empty($method)) {
$key = 'think_' . $this->getConfig('database') . '.' . $query->getTable() . '|' . $query->getOptions('key');
$key = 'think_' . $this->getConfig('database') . '.' . var_export($query->getTable(), true) . '|' . $query->getOptions('key');
} else {
$key = $query->getQueryGuid();
}
@ -378,7 +378,7 @@ abstract class Connection implements ConnectionInterface
{
foreach ($bind as $key => $val) {
$value = strval(is_array($val) ? $val[0] : $val);
$type = is_array($val) ? $val[1] : self::PARAM_STR;
$type = is_array($val) ? $val[1] : self::PARAM_STR;
if (self::PARAM_FLOAT == $type || self::PARAM_STR == $type) {
$value = '\'' . addslashes($value) . '\'';
@ -388,8 +388,11 @@ abstract class Connection implements ConnectionInterface
// 判断占位符
$sql = is_numeric($key) ?
substr_replace($sql, $value, strpos($sql, '?'), 1) :
substr_replace($sql, $value, strpos($sql, ':' . $key), strlen(':' . $key));
substr_replace($sql, $value, strpos($sql, '?'), 1) :
str_replace(
[':' . $key . ' ', ':' . $key . ',', ':' . $key . ')'],
[$value . ' ', $value . ',', $value . ')'],
$sql);
}
return rtrim($sql);

2
vendor/topthink/think-orm/src/db/ConnectionInterface.php vendored Executable file → Normal file
View File

@ -222,5 +222,5 @@ interface ConnectionInterface
*
* @return mixed
*/
public function getLastInsID(BaseQuery $query, string $sequence = null);
public function getLastInsID(BaseQuery $query, ?string $sequence = null);
}

52
vendor/topthink/think-orm/src/db/Fetch.php vendored Executable file → Normal file
View File

@ -9,7 +9,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db;
@ -43,8 +43,8 @@ class Fetch
*/
public function __construct(protected Query $query)
{
$this->connection = $query->getConnection();
$this->builder = $this->connection->getBuilder();
$this->connection = $query->getConnection();
$this->builder = $this->connection->getBuilder();
}
/**
@ -198,7 +198,7 @@ class Fetch
*
* @return string
*/
public function insertAll(array $dataSet = [], int $limit = null): string
public function insertAll(array $dataSet = [], ?int $limit = null): string
{
$options = $this->query->parseOptions();
@ -211,10 +211,10 @@ class Fetch
}
if ($limit) {
$array = array_chunk($dataSet, $limit, true);
$array = array_chunk($dataSet, $limit, true);
$fetchSql = [];
foreach ($array as $item) {
$sql = $this->builder->insertAll($this->query, $item);
$sql = $this->builder->insertAll($this->query, $item);
$bind = $this->query->getBind();
$fetchSql[] = $this->connection->getRealSql($sql, $bind);
@ -245,6 +245,34 @@ class Fetch
return $this->fetch($sql);
}
/**
* 字段值增长
*
* @param string $field 字段名
* @param float $step 步进值
* @param int $lazyTime 延迟时间(秒)
*
* @return string
*/
public function setInc(string $field, float $step = 1, int $lazyTime = 0)
{
return $this->inc($field, $step)->update();
}
/**
* 字段值减少
*
* @param string $field 字段名
* @param float $step 步进值
* @param int $lazyTime 延迟时间(秒)
*
* @return string
*/
public function setDec(string $field, float $step = 1, int $lazyTime = 0)
{
return $this->dec($field, $step)->update();
}
/**
* 更新记录.
*
@ -316,7 +344,7 @@ class Fetch
$this->query->setOption('soft_delete', null);
$this->query->setOption('data', [$field => $condition]);
// 生成删除SQL语句
$sql = $this->builder->delete($this->query);
$sql = $this->builder->update($this->query);
return $this->fetch($sql);
}
@ -437,12 +465,12 @@ class Fetch
if (!empty($options['group'])) {
// 支持GROUP
$subSql = $this->query->field('count(' . $field . ') AS think_count')->buildSql();
$query = $this->query->newQuery()->table([$subSql => '_group_count_']);
$query = $this->query->newQuery()->table([$subSql => '_group_count_']);
return $query->fetchsql()->aggregate('COUNT', '*');
} else {
return $this->aggregate('COUNT', $field);
}
return $this->aggregate('COUNT', $field);
}
/**
@ -500,7 +528,9 @@ class Fetch
$field = Str::snake(substr($method, 5));
return $this->where($field, '=', $args[0])->find();
} elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') {
}
if (strtolower(substr($method, 0, 10)) == 'getfieldby') {
// 根据某个字段获取记录的某个值
$name = Str::snake(substr($method, 10));

6
vendor/topthink/think-orm/src/db/Mongo.php vendored Executable file → Normal file
View File

@ -46,7 +46,7 @@ class Mongo extends BaseQuery
*
* @return mixed
*/
public function command(Command $command, string $dbName = '', ReadPreference $readPreference = null, $typeMap = null)
public function command(Command $command, string $dbName = '', ?ReadPreference $readPreference = null, $typeMap = null)
{
return $this->connection->command($command, $dbName, $readPreference, $typeMap);
}
@ -106,7 +106,7 @@ class Mongo extends BaseQuery
*
* @return int
*/
public function count(string $field = null): int
public function count(?string $field = null): int
{
$result = $this->cmd('count');
@ -462,7 +462,7 @@ class Mongo extends BaseQuery
*
* @return $this
*/
public function limit(int $offset, int $length = null)
public function limit(int $offset, ?int $length = null)
{
if (is_null($length)) {
$length = $offset;

287
vendor/topthink/think-orm/src/db/PDOConnection.php vendored Executable file → Normal file
View File

@ -9,7 +9,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db;
@ -163,12 +163,16 @@ abstract class PDOConnection extends Connection
protected $bindType = [
'string' => self::PARAM_STR,
'str' => self::PARAM_STR,
'bigint' => self::PARAM_STR,
'set' => self::PARAM_STR,
'enum' => self::PARAM_STR,
'integer' => self::PARAM_INT,
'int' => self::PARAM_INT,
'boolean' => self::PARAM_BOOL,
'bool' => self::PARAM_BOOL,
'float' => self::PARAM_FLOAT,
'datetime' => self::PARAM_STR,
'date' => self::PARAM_STR,
'timestamp' => self::PARAM_STR,
];
@ -276,10 +280,10 @@ abstract class PDOConnection extends Connection
{
// 字段大小写转换
return match ($this->attrCase) {
PDO::CASE_LOWER => array_change_key_case($info),
PDO::CASE_UPPER => array_change_key_case($info, CASE_UPPER),
PDO::CASE_NATURAL => $info,
default => $info,
PDO::CASE_LOWER => array_change_key_case($info),
PDO::CASE_UPPER => array_change_key_case($info, CASE_UPPER),
PDO::CASE_NATURAL => $info,
default => $info,
};
}
@ -292,25 +296,24 @@ abstract class PDOConnection extends Connection
*/
protected function getFieldType(string $type): string
{
if (0 === stripos($type, 'set') || 0 === stripos($type, 'enum')) {
$result = 'string';
} elseif (preg_match('/(double|float|decimal|real|numeric)/is', $type)) {
$result = 'float';
} elseif (preg_match('/(int|serial|bit)/is', $type)) {
$result = 'int';
} elseif (preg_match('/bool/is', $type)) {
$result = 'bool';
} elseif (0 === stripos($type, 'timestamp')) {
$result = 'timestamp';
} elseif (0 === stripos($type, 'datetime')) {
$result = 'datetime';
} elseif (0 === stripos($type, 'date')) {
$result = 'date';
} else {
$result = 'string';
}
// 将字段类型转换为小写以进行比较
$type = strtolower($type);
return $result;
return match (true) {
str_starts_with($type, 'set') => 'set',
str_starts_with($type, 'enum') => 'enum',
str_starts_with($type, 'bigint') => 'bigint',
str_contains($type, 'float') || str_contains($type, 'double') ||
str_contains($type, 'decimal') || str_contains($type, 'real') ||
str_contains($type, 'numeric') => 'float',
str_contains($type, 'int') || str_contains($type, 'serial') ||
str_contains($type, 'bit') => 'int',
str_contains($type, 'bool') => 'bool',
str_starts_with($type, 'timestamp') => 'timestamp',
str_starts_with($type, 'datetime') => 'datetime',
str_starts_with($type, 'date') => 'date',
default => 'string',
};
}
/**
@ -322,21 +325,7 @@ abstract class PDOConnection extends Connection
*/
public function getFieldBindType(string $type): int
{
if (in_array($type, ['integer', 'string', 'float', 'boolean', 'bool', 'int', 'str'])) {
$bind = $this->bindType[$type];
} elseif (str_starts_with($type, 'set') || str_starts_with($type, 'enum')) {
$bind = self::PARAM_STR;
} elseif (preg_match('/(double|float|decimal|real|numeric)/is', $type)) {
$bind = self::PARAM_FLOAT;
} elseif (preg_match('/(int|serial|bit)/is', $type)) {
$bind = self::PARAM_INT;
} elseif (preg_match('/bool/is', $type)) {
$bind = self::PARAM_BOOL;
} else {
$bind = self::PARAM_STR;
}
return $bind;
return $this->bindType[$type] ?? self::PARAM_STR;
}
/**
@ -348,7 +337,8 @@ abstract class PDOConnection extends Connection
*/
protected function getSchemaCacheKey(string $schema): string
{
return $this->getConfig('hostname') . '_' . $this->getConfig('hostport') . '|' . $schema;
$hostname = $this->getConfig('hostname');
return (is_array($hostname) ? $hostname[0] : $hostname) . '_' . $this->getConfig('hostport') . '|' . $schema;
}
/**
@ -357,49 +347,59 @@ abstract class PDOConnection extends Connection
*
* @return array
*/
public function getSchemaInfo(string $tableName, $force = false)
public function getSchemaInfo(string $tableName, bool $force = false): array
{
if (!str_contains($tableName, '.')) {
$schema = $this->getConfig('database') . '.' . $tableName;
} else {
$schema = $tableName;
$schema = str_contains($tableName, '.') ? $tableName : $this->getConfig('database') . '.' . $tableName;
if (isset($this->info[$schema]) && !$force) {
return $this->info[$schema];
}
if (!isset($this->info[$schema]) || $force) {
// 读取字段缓存
$cacheKey = $this->getSchemaCacheKey($schema);
if ($this->config['fields_cache'] && !empty($this->cache) && !$force) {
$info = $this->cache->get($cacheKey);
}
// 读取字段缓存
$cacheKey = $this->getSchemaCacheKey($schema);
$info = $this->getCachedSchemaInfo($cacheKey, $tableName, $force);
if (empty($info)) {
$info = $this->getTableFieldsInfo($tableName);
if (!empty($this->cache) && ($this->config['fields_cache'] || $force)) {
$this->cache->set($cacheKey, $info);
}
}
$pk = $info['_pk'] ?? null;
$autoinc = $info['_autoinc'] ?? null;
unset($info['_pk'], $info['_autoinc']);
$pk = $info['_pk'] ?? null;
$autoinc = $info['_autoinc'] ?? null;
unset($info['_pk'], $info['_autoinc']);
$bind = array_map(fn($val) => $this->getFieldBindType($val), $info);
$bind = [];
foreach ($info as $name => $val) {
$bind[$name] = $this->getFieldBindType($val);
}
$this->info[$schema] = [
'fields' => array_keys($info),
'type' => $info,
'bind' => $bind,
'pk' => $pk,
'autoinc' => $autoinc,
];
}
$this->info[$schema] = [
'fields' => array_keys($info),
'type' => $info,
'bind' => $bind,
'pk' => $pk,
'autoinc' => $autoinc,
];
return $this->info[$schema];
}
/**
* @param string $cacheKey 缓存key
* @param string $tableName 数据表名称
* @param bool $force 强制从数据库获取
*
* @return array
*/
protected function getCachedSchemaInfo(string $cacheKey, string $tableName, bool $force): array
{
if ($this->config['fields_cache'] && !empty($this->cache) && !$force) {
$info = $this->cache->get($cacheKey);
if (!empty($info)) {
return $info;
}
}
$info = $this->getTableFieldsInfo($tableName);
if (!empty($this->cache) && ($this->config['fields_cache'] || $force)) {
$this->cache->set($cacheKey, $info);
}
return $info;
}
/**
* 获取数据表信息.
*
@ -408,7 +408,7 @@ abstract class PDOConnection extends Connection
*
* @return mixed
*/
public function getTableInfo($tableName, string $fetch = '')
public function getTableInfo(array | string $tableName, string $fetch = '')
{
if (is_array($tableName)) {
$tableName = key($tableName) ?: current($tableName);
@ -423,7 +423,7 @@ abstract class PDOConnection extends Connection
$info = $this->getSchemaInfo($tableName);
return $fetch ? $info[$fetch] : $info;
return $fetch && isset($info[$fetch]) ? $info[$fetch] : $info;
}
/**
@ -436,7 +436,7 @@ abstract class PDOConnection extends Connection
public function getTableFieldsInfo(string $tableName): array
{
$fields = $this->getFields($tableName);
$info = [];
$info = [];
foreach ($fields as $key => $val) {
// 记录字段类型
@ -453,7 +453,7 @@ abstract class PDOConnection extends Connection
if (isset($pk)) {
// 设置主键
$pk = count($pk) > 1 ? $pk : $pk[0];
$pk = count($pk) > 1 ? $pk : $pk[0];
$info['_pk'] = $pk;
}
@ -508,7 +508,7 @@ abstract class PDOConnection extends Connection
*
* @return array|string
*/
public function getFieldsType($tableName, string $field = null)
public function getFieldsType($tableName, ?string $field = null)
{
$result = $this->getTableInfo($tableName, 'type');
@ -711,7 +711,7 @@ abstract class PDOConnection extends Connection
*
* @return array
*/
protected function pdoQuery(BaseQuery $query, $sql, bool $master = null): array
protected function pdoQuery(BaseQuery $query, $sql, ?bool $master = null): array
{
// 分析查询表达式
$query->parseOptions();
@ -723,16 +723,17 @@ abstract class PDOConnection extends Connection
if (!$query->getOptions('force_cache')) {
$key = $cacheItem->getKey();
$data = $this->cache->get($key);
if (null !== $data) {
return $data;
if ($this->cache->has($key)) {
$data = $this->cache->get($key);
if (null !== $data) {
return $data;
}
}
}
}
if ($sql instanceof Closure) {
$sql = $sql($query);
$sql = $sql($query);
$bind = $query->getBind();
}
@ -744,7 +745,7 @@ abstract class PDOConnection extends Connection
$this->getPDOStatement($sql, $bind, $master, $procedure);
$resultSet = $this->getResult($procedure);
$resultSet = $this->getResult($procedure);
$requireCache = $query->getOptions('cache_always') || !empty($resultSet);
if (isset($cacheItem) && $requireCache) {
@ -791,9 +792,8 @@ abstract class PDOConnection extends Connection
$this->initConnect($this->readMaster ?: $master);
// 记录SQL语句
$this->queryStr = $sql;
$this->bind = $bind;
$this->bind = $bind;
$this->db->updateQueryTimes();
$this->queryStartTime = microtime(true);
// 预处理
@ -817,7 +817,7 @@ abstract class PDOConnection extends Connection
$this->reConnectTimes = 0;
return $this->PDOStatement;
} catch (\Throwable | \Exception $e) {
} catch (\Throwable | \Exception $e) {
if ($this->transTimes > 0) {
// 事务活动中时不应该进行重试,应直接中断执行,防止造成污染。
if ($this->isBreak($e)) {
@ -868,8 +868,8 @@ abstract class PDOConnection extends Connection
if ($query->getOptions('cache')) {
// 清理缓存数据
$cacheItem = $this->parseCache($query, $query->getOptions('cache'));
$key = $cacheItem->getKey();
$tag = $cacheItem->getTag();
$key = $cacheItem->getKey();
$tag = $cacheItem->getTag();
if (isset($key) && $this->cache->has($key)) {
$this->cache->delete($key);
@ -891,9 +891,9 @@ abstract class PDOConnection extends Connection
*/
protected function queryPDOStatement(BaseQuery $query, string $sql): PDOStatement
{
$options = $query->getOptions();
$bind = $query->getBind();
$master = !empty($options['master']);
$options = $query->getOptions();
$bind = $query->getBind();
$master = !empty($options['master']);
$procedure = !empty($options['procedure']) || in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);
return $this->getPDOStatement($sql, $bind, $master, $procedure);
@ -989,14 +989,14 @@ abstract class PDOConnection extends Connection
$result = '' == $sql ? 0 : $this->pdoExecute($query, $sql);
if ($result) {
$sequence = $options['sequence'] ?? null;
$sequence = $options['sequence'] ?? null;
$lastInsId = $this->getLastInsID($query, $sequence);
$data = $options['data'];
if ($lastInsId) {
$pk = $query->getAutoInc();
if ($pk) {
if ($pk && is_string($pk)) {
$data[$pk] = $lastInsId;
}
}
@ -1057,7 +1057,7 @@ abstract class PDOConnection extends Connection
// 提交事务
$this->commit();
} catch (\Exception | \Throwable $e) {
} catch (\Exception | \Throwable $e) {
$this->rollback();
throw $e;
@ -1112,7 +1112,7 @@ abstract class PDOConnection extends Connection
// 提交事务
$this->commit();
} catch (\Exception | \Throwable $e) {
} catch (\Exception | \Throwable $e) {
$this->rollback();
throw $e;
@ -1230,7 +1230,10 @@ abstract class PDOConnection extends Connection
$key = $cacheItem->getKey();
if ($this->cache->has($key)) {
return $this->cache->get($key);
$data = $this->cache->get($key);
if (null !== $data) {
return $data;
}
}
}
}
@ -1251,28 +1254,30 @@ abstract class PDOConnection extends Connection
// 执行查询操作
$pdo = $this->getPDOStatement($sql, $query->getBind(), $options['master']);
$result = $pdo->fetchColumn();
$result = $pdo->fetchColumn();
$result = false !== $result ? $result : $default;
$requireCache = $query->getOptions('cache_always') || !empty($result);
if (isset($cacheItem)) {
if (isset($cacheItem) && $requireCache) {
// 缓存数据
$cacheItem->set($result);
$this->cacheData($cacheItem);
}
return false !== $result ? $result : $default;
return $result;
}
/**
* 得到某个字段的值
*
* @param BaseQuery $query 查询对象
* @param string $aggregate 聚合方法
* @param mixed $field 字段名
* @param bool $force 强制转为数字类型
* @param BaseQuery $query 查询对象
* @param string $aggregate 聚合方法
* @param string|Raw $field 字段名
* @param bool $force 强制转为数字类型
*
* @return mixed
*/
public function aggregate(BaseQuery $query, string $aggregate, $field, bool $force = false, bool $one = true)
public function aggregate(BaseQuery $query, string $aggregate, string | Raw $field, bool $force = false)
{
if (is_string($field) && 0 === stripos($field, 'DISTINCT ')) {
[$distinct, $field] = explode(' ', $field);
@ -1280,7 +1285,7 @@ abstract class PDOConnection extends Connection
$field = $aggregate . '(' . (!empty($distinct) ? 'DISTINCT ' : '') . $this->builder->parseKey($query, $field, true) . ') AS think_' . strtolower($aggregate);
$result = $this->value($query, $field, 0, $one);
$result = $this->value($query, $field, 0, false);
return $force ? (float) $result : $result;
}
@ -1294,7 +1299,7 @@ abstract class PDOConnection extends Connection
*
* @return array
*/
public function column(BaseQuery $query, string|array $column, string $key = ''): array
public function column(BaseQuery $query, string | array $column, string $key = ''): array
{
$options = $query->parseOptions();
@ -1329,7 +1334,10 @@ abstract class PDOConnection extends Connection
$name = $cacheItem->getKey();
if ($this->cache->has($name)) {
return $this->cache->get($name);
$data = $this->cache->get($name);
if (null !== $data) {
return $data;
}
}
}
}
@ -1344,7 +1352,7 @@ abstract class PDOConnection extends Connection
}
// 执行查询操作
$pdo = $this->getPDOStatement($sql, $query->getBind(), $options['master']);
$pdo = $this->getPDOStatement($sql, $query->getBind(), $options['master']);
$resultSet = $pdo->fetchAll(PDO::FETCH_ASSOC);
if (is_string($key) && str_contains($key, '.')) {
@ -1374,7 +1382,9 @@ abstract class PDOConnection extends Connection
$result = $resultSet;
}
if (isset($cacheItem)) {
$requireCache = $query->getOptions('cache_always') || !empty($result);
if (isset($cacheItem) && $requireCache) {
// 缓存数据
$cacheItem->set($result);
$this->cacheData($cacheItem);
@ -1516,15 +1526,12 @@ abstract class PDOConnection extends Connection
$this->startTrans();
try {
$result = null;
if (is_callable($callback)) {
$result = $callback($this);
}
$result = $callback($this);
$this->commit();
return $result;
} catch (\Exception | \Throwable $e) {
} catch (\Exception | \Throwable $e) {
$this->rollback();
throw $e;
@ -1544,19 +1551,17 @@ abstract class PDOConnection extends Connection
try {
$this->initConnect(true);
$this->transTimes++;
if (1 == $this->transTimes) {
if (0 == $this->transTimes) {
$this->linkID->beginTransaction();
} elseif ($this->transTimes > 1 && $this->supportSavepoint() && $this->linkID->inTransaction()) {
} elseif ($this->transTimes > 0 && $this->supportSavepoint() && $this->linkID->inTransaction()) {
$this->linkID->exec(
$this->parseSavepoint('trans' . $this->transTimes)
$this->parseSavepoint('trans' . ($this->transTimes + 1))
);
}
$this->transTimes++;
$this->reConnectTimes = 0;
} catch (\Throwable | \Exception $e) {
if (1 === $this->transTimes && $this->reConnectTimes < 4 && $this->isBreak($e)) {
$this->transTimes--;
} catch (\Throwable | \Exception $e) {
if (0 === $this->transTimes && $this->reConnectTimes < 4 && $this->isBreak($e)) {
$this->reConnectTimes++;
$this->close()->startTrans();
} else {
@ -1580,12 +1585,11 @@ abstract class PDOConnection extends Connection
public function commit(): void
{
$this->initConnect(true);
$this->transTimes = max(0, $this->transTimes - 1);
if (1 == $this->transTimes && $this->linkID->inTransaction()) {
if (0 == $this->transTimes && $this->linkID->inTransaction()) {
$this->linkID->commit();
}
$this->transTimes--;
}
/**
@ -1598,18 +1602,17 @@ abstract class PDOConnection extends Connection
public function rollback(): void
{
$this->initConnect(true);
$this->transTimes = max(0, $this->transTimes - 1);
if ($this->linkID->inTransaction()) {
if (1 == $this->transTimes) {
if (0 == $this->transTimes) {
$this->linkID->rollBack();
} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
} elseif ($this->transTimes > 0 && $this->supportSavepoint()) {
$this->linkID->exec(
$this->parseSavepointRollBack('trans' . $this->transTimes)
$this->parseSavepointRollBack('trans' . ($this->transTimes + 1))
);
}
}
$this->transTimes = max(0, $this->transTimes - 1);
}
/**
@ -1682,10 +1685,10 @@ abstract class PDOConnection extends Connection
*/
public function close()
{
$this->linkID = null;
$this->linkWrite = null;
$this->linkRead = null;
$this->links = [];
$this->linkID = null;
$this->linkWrite = null;
$this->linkRead = null;
$this->links = [];
$this->transTimes = 0;
$this->free();
@ -1735,7 +1738,7 @@ abstract class PDOConnection extends Connection
*
* @return mixed
*/
public function getLastInsID(BaseQuery $query, string $sequence = null)
public function getLastInsID(BaseQuery $query, ?string $sequence = null)
{
try {
$insertId = $this->linkID->lastInsertId($sequence);
@ -1758,7 +1761,7 @@ abstract class PDOConnection extends Connection
{
$pk = $query->getAutoInc();
if ($pk) {
if ($pk && is_string($pk)) {
$type = $this->getFieldsBind($query->getTable())[$pk];
if (self::PARAM_INT == $type) {
@ -1843,7 +1846,8 @@ abstract class PDOConnection extends Connection
if ($this->config['rw_separate']) {
// 主从式采用读写分离
if ($master) { // 主服务器写入
if ($master) {
// 主服务器写入
$r = $m;
} elseif (is_numeric($this->config['slave_no'])) {
// 指定服务器读
@ -1917,10 +1921,7 @@ abstract class PDOConnection extends Connection
}
try {
$result = null;
if (is_callable($callback)) {
$result = $callback($this);
}
$result = $callback($this);
foreach ($dbs as $db) {
$db->prepareXa($db->getUniqueXid('_' . $xid));
@ -1931,7 +1932,7 @@ abstract class PDOConnection extends Connection
}
return $result;
} catch (\Exception | \Throwable $e) {
} catch (\Exception | \Throwable $e) {
foreach ($dbs as $db) {
$db->rollbackXa($db->getUniqueXid('_' . $xid));
}

55
vendor/topthink/think-orm/src/db/Query.php vendored Executable file → Normal file
View File

@ -9,11 +9,13 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db;
use Closure;
use PDOStatement;
use ReflectionFunction;
use think\db\exception\DbException as Exception;
/**
@ -392,12 +394,12 @@ class Query extends BaseQuery
* 字段值增长(支持延迟写入)
*
* @param string $field 字段名
* @param int $step 步进值
* @param float $step 步进值
* @param int $lazyTime 延迟时间(秒)
*
* @return int|false
*/
public function setInc(string $field, int $step = 1, $lazyTime = 0)
public function setInc(string $field, float $step = 1, int $lazyTime = 0)
{
if (empty($this->options['where']) && $this->model) {
$this->where($this->model->getWhere());
@ -423,12 +425,12 @@ class Query extends BaseQuery
* 字段值减少(支持延迟写入)
*
* @param string $field 字段名
* @param int $step 步进值
* @param float $step 步进值
* @param int $lazyTime 延迟时间(秒)
*
* @return int|false
*/
public function setDec(string $field, int $step = 1, int $lazyTime = 0)
public function setDec(string $field, float $step = 1, int $lazyTime = 0)
{
if (empty($this->options['where']) && $this->model) {
$this->where($this->model->getWhere());
@ -457,11 +459,11 @@ class Query extends BaseQuery
* @access protected
* @param string $type 自增或者自减
* @param string $guid 写入标识
* @param int $step 写入步进值
* @param float $step 写入步进值
* @param int $lazyTime 延时时间(s)
* @return false|integer
*/
protected function lazyWrite(string $type, string $guid, int $step, int $lazyTime)
protected function lazyWrite(string $type, string $guid, float $step, int $lazyTime)
{
$cache = $this->getCache();
if (!$cache->has($guid . '_time')) {
@ -517,7 +519,30 @@ class Query extends BaseQuery
*/
public function getQueryGuid($data = null): string
{
return md5($this->getConfig('database') . serialize(var_export($data ?: $this->options, true)) . serialize($this->getBind(false)));
if (null === $data) {
$data = $this->options;
$data['table'] = $this->getConfig('database') . var_export($this->getTable(), true);
unset($data['scope'], $data['default_model']);
foreach (['AND', 'OR', 'XOR'] as $logic) {
if (isset($data['where'][$logic])) {
foreach ($data['where'][$logic] as $key => $val) {
if ($val instanceof Closure) {
$reflection = new ReflectionFunction($val);
$properties = $reflection->getStaticVariables();
if (empty($properties)) {
$name = $reflection->getName() . $reflection->getStartLine() . '-' . $reflection->getEndLine();
} else {
$name = var_export($properties, true);
}
$data['Closure'][] = $name;
unset($data['where'][$logic][$key]);
}
}
}
}
}
return md5(serialize(var_export($data, true)) . serialize($this->getBind(false)));
}
/**
@ -554,19 +579,19 @@ class Query extends BaseQuery
/**
* 分批数据返回处理.
*
* @param int $count 每次处理的数据数量
* @param callable $callback 处理回调方法
* @param string|array $column 分批处理的字段名
* @param string $order 字段排序
* @param int $count 每次处理的数据数量
* @param callable $callback 处理回调方法
* @param string|array|null $column 分批处理的字段名
* @param string $order 字段排序
*
* @throws Exception
*
* @return bool
*/
public function chunk(int $count, callable $callback, string|array $column = null, string $order = 'asc'): bool
public function chunk(int $count, callable $callback, string | array | null $column = null, string $order = 'asc'): bool
{
$options = $this->getOptions();
$column = $column ?: $this->getPk();
$column = $column ?: $this->getPk();
if (isset($options['order'])) {
unset($options['order']);
@ -598,7 +623,7 @@ class Query extends BaseQuery
$times++;
$query = $this->options($options)->page($times, $count);
} else {
$end = $resultSet->pop();
$end = $resultSet->pop();
$lastId = is_array($end) ? $end[$key] : $end->getData($key);
$query = $this->options($options)

2
vendor/topthink/think-orm/src/db/Raw.php vendored Executable file → Normal file
View File

@ -45,7 +45,7 @@ class Raw
/**
* 获取参数绑定.
*
* @return string
* @return array
*/
public function getBind(): array
{

2
vendor/topthink/think-orm/src/db/Where.php vendored Executable file → Normal file
View File

@ -168,7 +168,7 @@ class Where implements ArrayAccess
$this->__unset($name);
}
public function offsetGet(mixed $name)
public function offsetGet(mixed $name): mixed
{
return $this->__get($name);
}

1
vendor/topthink/think-orm/src/db/builder/Mongo.php vendored Executable file → Normal file
View File

@ -1,5 +1,4 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------

50
vendor/topthink/think-orm/src/db/builder/Mysql.php vendored Executable file → Normal file
View File

@ -9,14 +9,14 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db\builder;
use PDO;
use think\db\BaseQuery as Query;
use think\db\Builder;
use think\db\exception\DbException as Exception;
use think\db\BaseQuery as Query;
use think\db\Raw;
/**
@ -30,7 +30,7 @@ class Mysql extends Builder
* @var array
*/
protected $parser = [
'parseCompare' => ['=', '<>', '>', '>=', '<', '<='],
'parseCompare' => ['=', '!=', '<>', '>', '>=', '<', '<='],
'parseLike' => ['LIKE', 'NOT LIKE'],
'parseBetween' => ['NOT BETWEEN', 'BETWEEN'],
'parseIn' => ['NOT IN', 'IN'],
@ -161,8 +161,8 @@ class Mysql extends Builder
*/
public function insertAll(Query $query, array $dataSet): string
{
$options = $query->getOptions();
$bind = $query->getFieldsBindType();
$options = $query->getOptions();
$bind = $query->getFieldsBindType();
// 获取合法的字段
if (empty($options['field']) || '*' == $options['field']) {
@ -215,9 +215,9 @@ class Mysql extends Builder
public function insertAllByKeys(Query $query, array $keys, array $datas): string
{
$options = $query->getOptions();
$bind = $query->getFieldsBindType();
$fields = [];
$values = [];
$bind = $query->getFieldsBindType();
$fields = [];
$values = [];
foreach ($keys as $field) {
$fields[] = $this->parseKey($query, $field);
@ -259,8 +259,8 @@ class Mysql extends Builder
*/
public function update(Query $query): string
{
$options = $query->getOptions();
$data = $this->parseData($query, $options['data']);
$options = $query->getOptions();
$data = $this->parseData($query, $options['data']);
if (empty($data)) {
return '';
@ -367,11 +367,13 @@ class Mysql extends Builder
*
* @return string
*/
public function parseKey(Query $query, string|int|Raw $key, bool $strict = false): string
public function parseKey(Query $query, string | int | Raw $key, bool $strict = false): string
{
if (is_int($key)) {
return (string) $key;
} elseif ($key instanceof Raw) {
}
if ($key instanceof Raw) {
return $this->parseRaw($query, $key);
}
@ -382,12 +384,16 @@ class Mysql extends Builder
[$field, $name] = explode('->>', $key, 2);
return $this->parseKey($query, $field, true) . '->>\'$' . (str_starts_with($name, '[') ? '' : '.') . str_replace('->>', '.', $name) . '\'';
} elseif (str_contains($key, '->') && !str_contains($key, '(')) {
}
if (str_contains($key, '->') && !str_contains($key, '(')) {
// JSON字段支持
[$field, $name] = explode('->', $key, 2);
return 'json_extract(' . $this->parseKey($query, $field, true) . ', \'$' . (str_starts_with($name, '[') ? '' : '.') . str_replace('->', '.', $name) . '\')';
} elseif (str_contains($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
return 'json_unquote(json_extract(' . $this->parseKey($query, $field, true) . ', \'$' . (str_starts_with($name, '[') ? '' : '.') . str_replace('->', '.', $name) . '\'))';
}
if (str_contains($key, '.') && !preg_match('/[,\'\"\(\)`\s]/', $key)) {
[$table, $key] = explode('.', $key, 2);
$alias = $query->getOptions('alias');
@ -435,11 +441,11 @@ class Mysql extends Builder
*/
protected function parseNull(Query $query, string $key, string $exp, $value, $field, int $bindType): string
{
if (str_starts_with($key, "json_extract")) {
if ($exp === 'NULL') {
return '(' . $key . ' is null OR json_type(' . $key . ') = \'NULL\')';
}elseif ($exp === 'NOT NULL'){
return '(' . $key . ' is not null AND json_type(' . $key . ') != \'NULL\')';
if (str_starts_with($key, "json_unquote(json_extract")) {
if ('NULL' === $exp) {
return '(' . $key . ' is null OR ' . $key . ' = \'null\')';
} elseif ('NOT NULL' === $exp) {
return '(' . $key . ' is not null AND ' . $key . ' != \'null\')';
}
}
@ -504,12 +510,12 @@ class Mysql extends Builder
$updates = [];
foreach ($duplicate as $key => $val) {
if (is_numeric($key)) {
$val = $this->parseKey($query, $val);
$val = $this->parseKey($query, $val);
$updates[] = $val . ' = VALUES(' . $val . ')';
} elseif ($val instanceof Raw) {
$updates[] = $this->parseKey($query, $key) . ' = ' . $this->parseRaw($query, $val);
} else {
$name = $query->bindValue($val, $query->getConnection()->getFieldBindType($key));
$name = $query->bindValue($val, $query->getConnection()->getFieldBindType($key));
$updates[] = $this->parseKey($query, $key) . ' = :' . $name;
}
}

0
vendor/topthink/think-orm/src/db/builder/Oracle.php vendored Executable file → Normal file
View File

0
vendor/topthink/think-orm/src/db/builder/Pgsql.php vendored Executable file → Normal file
View File

0
vendor/topthink/think-orm/src/db/builder/Sqlite.php vendored Executable file → Normal file
View File

0
vendor/topthink/think-orm/src/db/builder/Sqlsrv.php vendored Executable file → Normal file
View File

71
vendor/topthink/think-orm/src/db/concern/AggregateQuery.php vendored Executable file → Normal file
View File

@ -9,7 +9,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db\concern;
@ -30,9 +30,9 @@ trait AggregateQuery
*
* @return mixed
*/
protected function aggregate(string $aggregate, string|Raw $field, bool $force = false, bool $one = false)
protected function aggregate(string $aggregate, string | Raw $field, bool $force = false)
{
return $this->connection->aggregate($this, $aggregate, $field, $force, $one);
return $this->connection->aggregate($this, $aggregate, $field, $force);
}
/**
@ -45,35 +45,38 @@ trait AggregateQuery
public function count(string $field = '*'): int
{
if (!empty($this->options['group'])) {
// 支持GROUP
if (!preg_match('/^[\w\.\*]+$/', $field)) {
throw new DbException('not support data:' . $field);
}
$options = $this->getOptions();
if (isset($options['cache'])) {
$cache = $options['cache'];
unset($options['cache']);
}
$subSql = $this->options($options)
->field('count(' . $field . ') AS think_count')
->bind($this->bind)
->buildSql();
$query = $this->newQuery();
if (isset($cache)) {
$query->setOption('cache', $cache);
}
$query->table([$subSql => '_group_count_']);
$count = $query->aggregate('COUNT', '*');
} else {
$count = $this->aggregate('COUNT', $field);
return $this->countWithGroup($field);
}
return (int) $count;
return (int) $this->aggregate('COUNT', $field);
}
protected function countWithGroup(string $field): int
{
if (!preg_match('/^[\w\.\*]+$/', $field)) {
throw new DbException('Not supported data: ' . $field);
}
$options = $this->getOptions();
$cache = $options['cache'] ?? null;
if (isset($options['cache'])) {
unset($options['cache']);
}
$subSql = $this->options($options)
->field('count(' . $field . ') AS think_count')
->bind($this->bind)
->buildSql();
$query = $this->newQuery();
if ($cache) {
$query->setOption('cache', $cache);
}
$query->table([$subSql => '_group_count_']);
return (int) $query->aggregate('COUNT', '*');
}
/**
@ -83,7 +86,7 @@ trait AggregateQuery
*
* @return float
*/
public function sum(string|Raw $field): float
public function sum(string | Raw $field): float
{
return $this->aggregate('SUM', $field, true);
}
@ -96,7 +99,7 @@ trait AggregateQuery
*
* @return mixed
*/
public function min(string|Raw $field, bool $force = true)
public function min(string | Raw $field, bool $force = true)
{
return $this->aggregate('MIN', $field, $force);
}
@ -109,7 +112,7 @@ trait AggregateQuery
*
* @return mixed
*/
public function max(string|Raw $field, bool $force = true)
public function max(string | Raw $field, bool $force = true)
{
return $this->aggregate('MAX', $field, $force);
}
@ -121,7 +124,7 @@ trait AggregateQuery
*
* @return float
*/
public function avg(string|Raw $field): float
public function avg(string | Raw $field): float
{
return $this->aggregate('AVG', $field, true);
}

147
vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php vendored Executable file → Normal file
View File

@ -9,11 +9,12 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db\concern;
use think\db\Raw;
use think\helper\Str;
/**
* JOIN和VIEW查询.
@ -30,7 +31,7 @@ trait JoinAndViewQuery
*
* @return $this
*/
public function join(array|string|Raw $join, string $condition = null, string $type = 'INNER', array $bind = [])
public function join(array | string | Raw $join, ?string $condition = null, string $type = 'INNER', array $bind = [])
{
$table = $this->getJoinTable($join);
@ -52,7 +53,7 @@ trait JoinAndViewQuery
*
* @return $this
*/
public function leftJoin(array|string|Raw $join, string $condition = null, array $bind = [])
public function leftJoin(array | string | Raw $join, ?string $condition = null, array $bind = [])
{
return $this->join($join, $condition, 'LEFT', $bind);
}
@ -66,7 +67,7 @@ trait JoinAndViewQuery
*
* @return $this
*/
public function rightJoin(array|string|Raw $join, string $condition = null, array $bind = [])
public function rightJoin(array | string | Raw $join, ?string $condition = null, array $bind = [])
{
return $this->join($join, $condition, 'RIGHT', $bind);
}
@ -80,9 +81,9 @@ trait JoinAndViewQuery
*
* @return $this
*/
public function fullJoin(array|string|Raw $join, string $condition = null, array $bind = [])
public function fullJoin(array | string | Raw $join, ?string $condition = null, array $bind = [])
{
return $this->join($join, $condition, 'FULL');
return $this->join($join, $condition, 'FULL', $bind);
}
/**
@ -94,37 +95,34 @@ trait JoinAndViewQuery
*
* @return string|array
*/
protected function getJoinTable(array|string|Raw $join, string &$alias = null)
protected function getJoinTable(array | string | Raw $join, ?string &$alias = null)
{
if (is_array($join)) {
$table = $join;
$alias = array_shift($join);
return $table;
} elseif ($join instanceof Raw) {
}
if ($join instanceof Raw || str_contains($join, '(')) {
return $join;
}
$join = trim($join);
if (str_contains($join, '(')) {
// 使用子查询
$table = $join;
} else {
// 使用别名
if (str_contains($join, ' ')) {
// 使用别名
if (str_contains($join, ' ')) {
// 使用别名
[$table, $alias] = explode(' ', $join);
} else {
$table = $join;
if (!str_contains($join, '.')) {
$alias = $join;
}
[$table, $alias] = explode(' ', $join);
} else {
$table = $join;
if (!str_contains($join, '.')) {
$alias = $join;
}
}
if ($this->prefix && !str_contains($table, '.') && !str_starts_with($table, $this->prefix)) {
$table = $this->getTable($table);
}
if ($this->prefix && !str_contains($table, '.') && !str_starts_with($table, $this->prefix)) {
$table = $this->prefix . Str::snake($table) . $this->suffix;
}
if (!empty($alias) && $table != $alias) {
@ -145,41 +143,19 @@ trait JoinAndViewQuery
*
* @return $this
*/
public function view(array|string|Raw $join, string|array|bool $field = true, string $on = null, string $type = 'INNER', array $bind = [])
public function view(array | string | Raw $join, string | array | bool $field = true, ?string $on = null, string $type = 'INNER', array $bind = []): self
{
$this->options['view'] = true;
$fields = [];
$table = $this->getJoinTable($join, $alias);
$table = $this->getJoinTable($join, $alias);
if (true === $field) {
$fields = $alias . '.*';
} else {
if (is_string($field)) {
$field = explode(',', $field);
}
foreach ($field as $key => $val) {
if (is_numeric($key)) {
$fields[] = $alias . '.' . $val;
$this->options['map'][$val] = $alias . '.' . $val;
} else {
if (preg_match('/[,=\.\'\"\(\s]/', $key)) {
$name = $key;
} else {
$name = $alias . '.' . $key;
}
$fields[] = $name . ' AS ' . $val;
$this->options['map'][$val] = $name;
}
}
}
// 处理字段
$fields = $this->processFields($field, $alias);
$this->field($fields);
// 处理连接
if ($on) {
$this->join($table, $on, $type, $bind);
} else {
@ -189,6 +165,28 @@ trait JoinAndViewQuery
return $this;
}
protected function processFields(string | array | bool $field, string $alias): array
{
$fields = [];
if (true === $field) {
$fields[] = $alias . '.*'; // 选取所有字段
} else {
if (is_string($field)) {
$field = explode(',', $field);
}
foreach ($field as $key => $val) {
$name = is_numeric($key) ? $alias . '.' . $val : (preg_match('/[,=\.\'\"\(\s]/', $key) ? $key : $alias . '.' . $key);
$fields[] = $name . (is_numeric($key) ? '' : ' AS ' . $val);
$this->options['map'][$val] = $name;
}
}
return $fields;
}
/**
* 视图查询处理.
*
@ -199,36 +197,41 @@ trait JoinAndViewQuery
protected function parseView(array &$options): void
{
foreach (['AND', 'OR'] as $logic) {
if (isset($options['where'][$logic])) {
foreach ($options['where'][$logic] as $key => $val) {
if (array_key_exists($key, $options['map'])) {
array_shift($val);
array_unshift($val, $options['map'][$key]);
$options['where'][$logic][$options['map'][$key]] = $val;
unset($options['where'][$logic][$key]);
}
if (!isset($options['where'][$logic])) {
continue;
}
// 视图查询条件处理
foreach ($options['where'][$logic] as $key => $val) {
if (array_key_exists($key, $options['map'])) {
array_shift($val);
array_unshift($val, $options['map'][$key]);
$options['where'][$logic][$options['map'][$key]] = $val;
unset($options['where'][$logic][$key]);
}
}
}
if (isset($options['order'])) {
// 视图查询排序处理
foreach ($options['order'] as $key => $val) {
if (is_numeric($key) && is_string($val)) {
if (str_contains($val, ' ')) {
[$field, $sort] = explode(' ', $val);
if (array_key_exists($field, $options['map'])) {
$options['order'][$options['map'][$field]] = $sort;
unset($options['order'][$key]);
}
} elseif (array_key_exists($val, $options['map'])) {
$options['order'][$options['map'][$val]] = 'asc';
if (empty($options['order'])) {
return;
}
// 视图查询排序处理
foreach ($options['order'] as $key => $val) {
if (is_numeric($key) && is_string($val)) {
if (str_contains($val, ' ')) {
[$field, $sort] = explode(' ', $val);
if (array_key_exists($field, $options['map'])) {
$options['order'][$options['map'][$field]] = $sort;
unset($options['order'][$key]);
}
} elseif (array_key_exists($key, $options['map'])) {
$options['order'][$options['map'][$key]] = $val;
} elseif (array_key_exists($val, $options['map'])) {
$options['order'][$options['map'][$val]] = 'asc';
unset($options['order'][$key]);
}
} elseif (array_key_exists($key, $options['map'])) {
$options['order'][$options['map'][$key]] = $val;
unset($options['order'][$key]);
}
}
}

169
vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php vendored Executable file → Normal file
View File

@ -9,7 +9,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db\concern;
@ -58,12 +58,13 @@ trait ModelRelationQuery
* 设置需要隐藏的输出属性.
*
* @param array $hidden 属性列表
* @param bool $merge 是否合并
*
* @return $this
*/
public function hidden(array $hidden = [])
public function hidden(array $hidden, bool $merge = false)
{
$this->options['hidden'] = $hidden;
$this->options['hidden'] = [$hidden, $merge];
return $this;
}
@ -71,13 +72,14 @@ trait ModelRelationQuery
/**
* 设置需要输出的属性.
*
* @param array $visible
* @param array $visible 属性列表
* @param bool $merge 是否合并
*
* @return $this
*/
public function visible(array $visible = [])
public function visible(array $visible, bool $merge = false)
{
$this->options['visible'] = $visible;
$this->options['visible'] = [$visible, $merge];
return $this;
}
@ -86,12 +88,27 @@ trait ModelRelationQuery
* 设置需要附加的输出属性.
*
* @param array $append 属性列表
* @param bool $merge 是否合并
*
* @return $this
*/
public function append(array $append = [])
public function append(array $append, bool $merge = false)
{
$this->options['append'] = $append;
$this->options['append'] = [$append, $merge];
return $this;
}
/**
* 设置模型的输出映射.
*
* @param array $mapping 映射列表
*
* @return $this
*/
public function mapping(array $mapping)
{
$this->options['mapping'] = $mapping;
return $this;
}
@ -110,22 +127,20 @@ trait ModelRelationQuery
array_unshift($args, $this);
if ($scope instanceof Closure) {
call_user_func_array($scope, $args);
$this->options['scope'][] = [$scope, $args];
return $this;
}
if (is_string($scope)) {
$scope = explode(',', $scope);
}
if ($this->model) {
if (is_string($scope)) {
$scope = explode(',', $scope);
}
// 检查模型类的查询范围方法
foreach ($scope as $name) {
$method = 'scope' . trim($name);
if (method_exists($this->model, $method)) {
call_user_func_array([$this->model, $method], $args);
$this->options['scope'][$name] = [[$this->model, $method], $args];
}
}
}
@ -133,6 +148,46 @@ trait ModelRelationQuery
return $this;
}
/**
* 执行查询范围查询.
*
* @return $this
*/
protected function scopeQuery()
{
if (!empty($this->options['scope'])) {
foreach ($this->options['scope'] as $val) {
[$call, $args] = $val;
call_user_func_array($call, $args);
}
}
return $this;
}
/**
* 指定不使用的查询范围.
*
* @param array $scope 查询范围
*
* @return $this
*/
public function withoutScope(array $scope = [])
{
if (empty($scope)) {
$this->options['scope'] = [];
return $this;
}
foreach ($scope as $name) {
if (isset($this->options['scope'][$name])) {
unset($this->options['scope'][$name]);
}
}
return $this;
}
/**
* 设置关联查询.
*
@ -156,11 +211,11 @@ trait ModelRelationQuery
*
* @param string|array $fields 搜索字段
* @param mixed $data 搜索数据
* @param string $prefix 字段前缀标识
* @param bool $strict 是否严格检查数据
*
* @return $this
*/
public function withSearch($fields, $data = [], string $prefix = '')
public function withSearch($fields, $data = [], bool $strict = true)
{
if (is_string($fields)) {
$fields = explode(',', $fields);
@ -170,14 +225,17 @@ trait ModelRelationQuery
foreach ($fields as $key => $field) {
if ($field instanceof Closure) {
$field($this, $data[$key] ?? null, $data, $prefix);
$field($this, $data[$key] ?? null, $data);
} elseif ($this->model) {
// 检测搜索器
$fieldName = is_numeric($key) ? $field : $key;
$method = 'search' . Str::studly($fieldName) . 'Attr';
// 检查字段是否有数据
if ($strict && (!isset($data[$field]) || (empty($data[$field]) && !in_array($data[$field], ['0', 0])))) {
continue;
}
$fieldName = is_numeric($key) ? $field : $key;
$method = 'search' . Str::studly($fieldName) . 'Attr';
if (method_exists($this->model, $method)) {
$this->model->$method($this, $data[$field] ?? null, $data, $prefix);
$this->model->$method($this, $data[$field], $data);
} elseif (isset($data[$field])) {
$this->where($fieldName, in_array($fieldName, $likeFields) ? 'like' : '=', in_array($fieldName, $likeFields) ? '%' . $data[$field] . '%' : $data[$field]);
}
@ -229,6 +287,19 @@ trait ModelRelationQuery
return $this;
}
/**
* 设置关联模型的动态绑定
*
* @param array $attr 绑定数据
*
* @return $this
*/
public function withBind(array $attr)
{
$this->options['bind_attr'] = $attr;
return $this;
}
/**
* 设置数据字段获取器.
*
@ -237,7 +308,7 @@ trait ModelRelationQuery
*
* @return $this
*/
public function withAttr(string|array $name, callable $callback = null)
public function withAttr(string | array $name, ?callable $callback = null)
{
if (is_array($name)) {
foreach ($name as $key => $val) {
@ -269,7 +340,7 @@ trait ModelRelationQuery
*
* @return $this
*/
public function with(array|string $with)
public function with(array | string $with)
{
if (empty($this->model) || empty($with)) {
return $this;
@ -288,25 +359,25 @@ trait ModelRelationQuery
*
* @return $this
*/
public function withJoin(array|string $with, string $joinType = '')
public function withJoin(array | string $with, string $joinType = '')
{
if (empty($this->model) || empty($with)) {
return $this;
}
$with = (array) $with;
$with = (array) $with;
$first = true;
foreach ($with as $key => $relation) {
$closure = null;
$field = true;
$field = true;
if ($relation instanceof Closure) {
// 支持闭包查询过滤关联条件
$closure = $relation;
$closure = $relation;
$relation = $key;
} elseif (is_array($relation)) {
$field = $relation;
$field = $relation;
$relation = $key;
} elseif (is_string($relation) && str_contains($relation, '.')) {
$relation = strstr($relation, '.', true);
@ -337,7 +408,7 @@ trait ModelRelationQuery
*
* @return $this
*/
protected function withAggregate(string|array $relations, string $aggregate = 'count', $field = '*', bool $subQuery = true)
protected function withAggregate(string | array $relations, string $aggregate = 'count', $field = '*', bool $subQuery = true)
{
if (empty($this->model)) {
return $this;
@ -368,7 +439,7 @@ trait ModelRelationQuery
*
* @return $this
*/
public function withCache(string|array|bool $relation = true, $key = true, $expire = null, string $tag = null)
public function withCache(string | array | bool $relation = true, $key = true, $expire = null, ?string $tag = null)
{
if (empty($this->model)) {
return $this;
@ -378,9 +449,9 @@ trait ModelRelationQuery
return $this;
}
if ($key instanceof \DateTimeInterface || $key instanceof \DateInterval || (is_int($key) && is_null($expire))) {
if ($key instanceof \DateTimeInterface || $key instanceof \DateInterval || (is_int($key) && is_null($expire))) {
$expire = $key;
$key = true;
$key = true;
}
if (true === $relation || is_numeric($relation)) {
@ -409,7 +480,7 @@ trait ModelRelationQuery
*
* @return $this
*/
public function withCount(string|array $relation, bool $subQuery = true)
public function withCount(string | array $relation, bool $subQuery = true)
{
return $this->withAggregate($relation, 'count', '*', $subQuery);
}
@ -423,7 +494,7 @@ trait ModelRelationQuery
*
* @return $this
*/
public function withSum(string|array $relation, string $field, bool $subQuery = true)
public function withSum(string | array $relation, string $field, bool $subQuery = true)
{
return $this->withAggregate($relation, 'sum', $field, $subQuery);
}
@ -437,7 +508,7 @@ trait ModelRelationQuery
*
* @return $this
*/
public function withMax(string|array $relation, string $field, bool $subQuery = true)
public function withMax(string | array $relation, string $field, bool $subQuery = true)
{
return $this->withAggregate($relation, 'max', $field, $subQuery);
}
@ -451,7 +522,7 @@ trait ModelRelationQuery
*
* @return $this
*/
public function withMin(string|array $relation, string $field, bool $subQuery = true)
public function withMin(string | array $relation, string $field, bool $subQuery = true)
{
return $this->withAggregate($relation, 'min', $field, $subQuery);
}
@ -465,7 +536,7 @@ trait ModelRelationQuery
*
* @return $this
*/
public function withAvg(string|array $relation, string $field, bool $subQuery = true)
public function withAvg(string | array $relation, string $field, bool $subQuery = true)
{
return $this->withAggregate($relation, 'avg', $field, $subQuery);
}
@ -517,6 +588,9 @@ trait ModelRelationQuery
}
$jsonData = json_decode($result[$name], true);
if (json_last_error() !== JSON_ERROR_NONE) {
continue;
}
if (isset($withAttr[$name])) {
foreach ($withAttr[$name] as $key => $closure) {
@ -583,7 +657,9 @@ trait ModelRelationQuery
if (!empty($this->options['lazy_fields'])) {
$id = $this->getKey($result);
foreach ($this->options['lazy_fields'] as $field) {
$result[$field] += $this->getLazyFieldValue($field, $id);
if (isset($result[$field])) {
$result[$field] += $this->getLazyFieldValue($field, $id);
}
}
}
@ -593,6 +669,10 @@ trait ModelRelationQuery
$this->options
);
if ($this->suffix) {
$result->setSuffix($this->suffix);
}
// 模型数据处理
foreach ($this->options['filter'] as $filter) {
call_user_func_array($filter, [$result, $this->options]);
@ -626,12 +706,17 @@ trait ModelRelationQuery
// 动态获取器
if (!empty($this->options['with_attr'])) {
$result->withAttr($this->options['with_attr']);
$result->withFieldAttr($this->options['with_attr']);
}
if (!empty($this->options['mapping'])) {
$result->mapping($this->options['mapping']);
}
foreach (['hidden', 'visible', 'append'] as $name) {
if (!empty($this->options[$name])) {
$result->$name($this->options[$name]);
[$value, $merge] = $this->options[$name];
$result->$name($value, $merge);
}
}

11
vendor/topthink/think-orm/src/db/concern/ParamsBind.php vendored Executable file → Normal file
View File

@ -9,7 +9,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db\concern;
@ -50,7 +50,7 @@ trait ParamsBind
*
* @return string
*/
public function bindValue($value, int $type = null, string $name = null)
public function bindValue($value, ?int $type = null, ?string $name = null)
{
$name = $name ?: 'ThinkBind_' . (count($this->bind) + 1) . '_' . mt_rand() . '_';
@ -119,8 +119,13 @@ trait ParamsBind
if (is_numeric($key)) {
$sql = substr_replace($sql, ':' . $name, strpos($sql, '?'), 1);
} elseif (str_ends_with($sql, ':' . $key)) {
$sql = substr_replace($sql, ':' . $name . ' ', strrpos($sql, ':' . $key), strlen(':' . $key));
} else {
$sql = str_replace(':' . $key, ':' . $name, $sql);
$sql = str_replace(
[':' . $key . ' ', ':' . $key . ',', ':' . $key . ')'],
[':' . $name . ' ', ':' . $name . ',', ':' . $name . ')'],
$sql);
}
}
}

24
vendor/topthink/think-orm/src/db/concern/ResultOperation.php vendored Executable file → Normal file
View File

@ -9,7 +9,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db\concern;
@ -35,7 +35,7 @@ trait ResultOperation
*
* @return $this
*/
public function filter(callable $filter, string $index = null)
public function filter(callable $filter, ?string $index = null)
{
if ($index) {
$this->options['filter'][$index] = $filter;
@ -105,6 +105,16 @@ trait ResultOperation
if (!empty($this->options['with_attr'])) {
$this->getResultAttr($result, $this->options['with_attr']);
}
// 检查字段映射
if (!empty($this->options['mapping'])) {
foreach ($this->options['mapping'] as $name => $alias) {
if (isset($result[$name])) {
$result[$alias] = $result[$name];
unset($result[$name]);
}
}
}
}
/**
@ -155,17 +165,19 @@ trait ResultOperation
/**
* 处理空数据.
*
* @param Closure $closure 闭包数据
* @throws DbException
* @throws ModelNotFoundException
* @throws DataNotFoundException
*
* @return array|Model|null|static
*/
protected function resultToEmpty()
protected function resultToEmpty(?Closure $closure = null)
{
if (!empty($this->options['fail'])) {
$this->throwNotFound();
} elseif ($closure instanceof Closure) {
return $closure($this);
} elseif (!empty($this->options['allow_empty'])) {
return !empty($this->model) ? $this->model->newInstance() : [];
}
@ -214,12 +226,12 @@ trait ResultOperation
if (!empty($this->model)) {
$class = get_class($this->model);
throw new ModelNotFoundException('model data Not Found:'.$class, $class, $this->options);
throw new ModelNotFoundException('model data Not Found:' . $class, $class, $this->options);
}
$table = $this->getTable();
throw new DataNotFoundException('table data not Found:'.$table, $table, $this->options);
throw new DataNotFoundException('table data not Found:' . $table, $table, $this->options);
}
/**

0
vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php vendored Executable file → Normal file
View File

4
vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php vendored Executable file → Normal file
View File

@ -100,6 +100,10 @@ trait TimeFieldQuery
public function whereMonth(string $field, string $month = 'this month', int $step = 1, string $logic = 'AND')
{
if (in_array($month, ['this month', 'last month'])) {
if($month === 'last month') {
$month = $this->timeRule['last month'][0];
}
$month = date('Y-m', strtotime($month));
}

0
vendor/topthink/think-orm/src/db/concern/Transaction.php vendored Executable file → Normal file
View File

156
vendor/topthink/think-orm/src/db/concern/WhereQuery.php vendored Executable file → Normal file
View File

@ -9,7 +9,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db\concern;
@ -37,18 +37,26 @@ trait WhereQuery
} elseif (true === $field || 1 === $field) {
$this->options['where']['AND'][] = true;
return $this;
} elseif (empty($field)) {
return $this;
}
$pk = $this->getPk();
if ((is_null($condition) || '=' == $op) && is_string($pk) && $pk == $field ) {
if ((is_null($condition) || '=' == $op) && is_string($pk) && $pk == $field) {
$this->options['key'] = is_null($condition) ? $op : $condition;
}
$logic = 'AND';
$param = func_get_args();
array_shift($param);
return $this->parseWhereExp('AND', $field, $op, $condition, $param);
if (is_array($field) && !empty($field) && array_is_list($field)) {
return $this->where(function ($query) use ($param, $condition, $op, $field, $logic) {
return $query->parseWhereExp($logic, $field, $op, $condition, $param);
});
}
return $this->parseWhereExp($logic, $field, $op, $condition, $param);
}
/**
@ -61,6 +69,7 @@ trait WhereQuery
protected function parseQueryWhere(BaseQuery $query): void
{
$this->options['where'] = $query->getOptions('where') ?? [];
$via = $query->getOptions('via');
if ($via) {
@ -87,10 +96,17 @@ trait WhereQuery
*/
public function whereOr($field, $op = null, $condition = null)
{
$logic = 'OR';
$param = func_get_args();
array_shift($param);
return $this->parseWhereExp('OR', $field, $op, $condition, $param);
if (is_array($field) && !empty($field) && array_is_list($field)) {
return $this->where(function ($query) use ($param, $condition, $op, $field, $logic) {
return $query->parseWhereExp($logic, $field, $op, $condition, $param);
});
}
return $this->parseWhereExp($logic, $field, $op, $condition, $param);
}
/**
@ -104,10 +120,16 @@ trait WhereQuery
*/
public function whereXor($field, $op = null, $condition = null)
{
$logic = 'XOR';
$param = func_get_args();
array_shift($param);
return $this->parseWhereExp('XOR', $field, $op, $condition, $param);
if (is_array($field) && !empty($field) && array_is_list($field)) {
return $this->where(function ($query) use ($param, $condition, $op, $field, $logic) {
return $query->parseWhereExp($logic, $field, $op, $condition, $param);
});
}
return $this->parseWhereExp($logic, $field, $op, $condition, $param);
}
/**
@ -272,6 +294,33 @@ trait WhereQuery
return $this->parseWhereExp($logic, $field, 'FIND IN SET', $condition, [], true);
}
/**
* 指定json_contains查询条件.
*
* @param mixed $field 查询字段
* @param mixed $condition 查询条件
* @param string $logic 查询逻辑 and or xor
*
* @return $this
*/
public function whereJsonContains(string $field, $condition, string $logic = 'AND')
{
if (str_contains($field, '->')) {
[$field1, $field2] = explode('->', $field);
$field = 'json_extract(' . $field1 . ',\'$.' . $field2 . '\')';
}
$value = is_string($condition) ? '"' . $condition . '"' : $condition;
$name = $this->bindValue($value);
$bind[$name] = $value;
return $this->whereRaw('json_contains(' . $field . ',:' . $name . ')', $bind, $logic);
}
public function whereOrJsonContains(string $field, $condition)
{
return $this->whereJsonContains($field, $condition, 'OR');
}
/**
* 比较两个字段.
*
@ -282,10 +331,10 @@ trait WhereQuery
*
* @return $this
*/
public function whereColumn(string $field1, string $operator, string $field2 = null, string $logic = 'AND')
public function whereColumn(string $field1, string $operator, ?string $field2 = null, string $logic = 'AND')
{
if (is_null($field2)) {
$field2 = $operator;
$field2 = $operator;
$operator = '=';
}
@ -309,6 +358,20 @@ trait WhereQuery
return $this;
}
/**
* 包含软删除数据.
*
* @return $this
*/
public function withTrashed()
{
if ($this->model) {
$this->options['soft_delete'] = null;
}
return $this;
}
/**
* 指定Exp查询条件.
*
@ -340,7 +403,7 @@ trait WhereQuery
{
if (is_null($condition)) {
$condition = $op;
$op = '=';
$op = '=';
}
$this->options['where'][$logic][] = [new Raw($field), $op, $condition];
@ -389,39 +452,41 @@ trait WhereQuery
*
* @return $this
*/
protected function parseWhereExp(string $logic, $field, $op, $condition, array $param = [], bool $strict = false)
protected function parseWhereExp(string $logic, $field, $op, $condition, array $param = [], bool $strict = false): self
{
$logic = strtoupper($logic);
// 处理 via
if (is_string($field) && !empty($this->options['via']) && !str_contains($field, '.')) {
$field = $this->options['via'] . '.' . $field;
}
// 严格模式查询
if ($strict) {
// 使用严格模式查询
if ('=' == $op) {
$where = $this->whereEq($field, $condition);
} else {
$where = [$field, $op, $condition, $logic];
}
} elseif (is_array($field)) {
// 解析数组批量查询
return $this->parseStrictWhere($field, $op, $condition, $logic);
}
// 处理批量查询
if (is_array($field)) {
return $this->parseArrayWhereItems($field, $logic);
} elseif ($field instanceof Closure) {
}
// 处理闭包查询
if ($field instanceof Closure) {
$where = $field;
} elseif (is_string($field)) {
if ($condition instanceof Raw) {
} elseif (preg_match('/[,=\<\'\"\(\s]/', $field)) {
return $this->whereRaw($field, is_array($op) ? $op : [], $logic);
} elseif (is_string($op) && strtolower($op) == 'exp' && !is_null($condition)) {
} elseif (is_string($op) && strtolower($op) === 'exp' && !is_null($condition)) {
$bind = isset($param[2]) && is_array($param[2]) ? $param[2] : [];
return $this->whereExp($field, $condition, $bind, $logic);
}
$where = $this->parseWhereItem($logic, $field, $op, $condition, $param);
}
// 添加条件到查询选项
if (!empty($where)) {
$this->options['where'][$logic][] = $where;
}
@ -429,6 +494,19 @@ trait WhereQuery
return $this;
}
protected function parseStrictWhere($field, $op, $condition, string $logic): self
{
if ('=' === $op) {
$where = $this->whereEq($field, $condition);
} else {
$where = [$field, $op, $condition, $logic];
}
$this->options['where'][$logic][] = $where;
return $this;
}
/**
* 分析查询表达式.
*
@ -445,8 +523,10 @@ trait WhereQuery
if (is_array($op)) {
// 同一字段多条件查询
array_unshift($param, $field);
$where = $param;
} elseif ($field && is_null($condition)) {
return $param;
}
if ($field && is_null($condition)) {
if (is_string($op) && in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) {
// null查询
$where = [$field, $op, ''];
@ -458,7 +538,10 @@ trait WhereQuery
// 字段相等查询
$where = $this->whereEq($field, $op);
}
} elseif (is_string($op) && in_array(strtoupper($op), ['EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) {
return $where;
}
if (is_string($op) && in_array(strtoupper($op), ['EXISTS', 'NOT EXISTS', 'NOTEXISTS'], true)) {
$where = [$field, $op, is_string($condition) ? new Raw($condition) : $condition];
} else {
$where = $field ? [$field, $op, $condition, $param[2] ?? null] : [];
@ -507,7 +590,7 @@ trait WhereQuery
if (!empty($where)) {
$this->options['where'][$logic] = isset($this->options['where'][$logic]) ?
array_merge($this->options['where'][$logic], $where) : $where;
array_merge($this->options['where'][$logic], $where) : $where;
}
return $this;
@ -545,26 +628,29 @@ trait WhereQuery
*
* @return $this
*/
public function when($condition, $query, $otherwise = null)
public function when($condition, Closure | array $query, Closure | array | null $otherwise = null): self
{
// 处理条件为 Closure 的情况
if ($condition instanceof Closure) {
$condition = $condition($this);
}
// 根据条件决定执行哪个查询
if ($condition) {
if ($query instanceof Closure) {
$query($this, $condition);
} elseif (is_array($query)) {
$this->where($query);
}
$this->executeQuery($query, $condition);
} elseif ($otherwise) {
if ($otherwise instanceof Closure) {
$otherwise($this, $condition);
} elseif (is_array($otherwise)) {
$this->where($otherwise);
}
$this->executeQuery($otherwise, $condition);
}
return $this;
}
protected function executeQuery(Closure | array $query, $condition): void
{
if ($query instanceof Closure) {
$query($this, $condition);
} elseif (is_array($query)) {
$this->where($query);
}
}
}

107
vendor/topthink/think-orm/src/db/connector/Mongo.php vendored Executable file → Normal file
View File

@ -7,7 +7,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db\connector;
@ -42,7 +42,7 @@ use think\db\Mongo as Query;
class Mongo extends Connection
{
// 查询数据类型
protected $dbName = '';
protected $dbName = '';
protected $typeMap = 'array';
protected $mongo; // MongoDb Object
protected $cursor; // MongoCursor Object
@ -94,6 +94,10 @@ class Mongo extends Connection
'fields_cache' => false,
// 监听SQL
'trigger_sql' => true,
// Builder类
'builder' => '',
// Query类
'query' => '',
// 自动写入时间戳字段
'auto_timestamp' => false,
// 时间字段取出后的默认时间格式
@ -111,7 +115,7 @@ class Mongo extends Connection
*/
public function getQueryClass(): string
{
return Query::class;
return $this->getConfig('query') ?: Query::class;
}
/**
@ -131,7 +135,7 @@ class Mongo extends Connection
*/
public function getBuilderClass(): string
{
return Builder::class;
return $this->getConfig('builder') ?: Builder::class;
}
/**
@ -154,7 +158,7 @@ class Mongo extends Connection
$config = array_merge($this->config, $config);
}
$this->dbName = $config['database'];
$this->dbName = $config['database'];
$this->typeMap = $config['type_map'];
if ($config['pk_convert_id'] && '_id' == $config['pk']) {
@ -195,7 +199,7 @@ class Mongo extends Connection
*
* @return string
*/
public function db(string $db = null)
public function db(?string $db = null)
{
if (is_null($db)) {
return $this->dbName;
@ -243,8 +247,8 @@ class Mongo extends Connection
$this->initConnect($master);
$this->db->updateQueryTimes();
$options = $query->getOptions();
$namespace = $options['table'];
$options = $query->getOptions();
$namespace = $options['table'];
if (!str_contains($namespace, '.')) {
$namespace = $this->dbName . '.' . $namespace;
@ -259,7 +263,7 @@ class Mongo extends Connection
$mongoQuery = $mongoQuery($query);
}
$readPreference = $options['readPreference'] ?? null;
$readPreference = $options['readPreference'] ?? null;
$this->queryStartTime = microtime(true);
if ($session = $this->getSession()) {
@ -333,8 +337,8 @@ class Mongo extends Connection
if ($query->getOptions('cache')) {
// 检查查询缓存
$cacheItem = $this->parseCache($query, $query->getOptions('cache'));
$key = $cacheItem->getKey();
$cacheItem = $this->parseCache($query, $query->getOptions('cache'));
$key = $cacheItem->getKey();
if ($this->cache->has($key)) {
return $this->cache->get($key);
@ -378,8 +382,8 @@ class Mongo extends Connection
$this->initConnect(true);
$this->db->updateQueryTimes();
$options = $query->getOptions();
$namespace = $options['table'];
$options = $query->getOptions();
$namespace = $options['table'];
if (!str_contains($namespace, '.')) {
$namespace = $this->dbName . '.' . $namespace;
}
@ -389,7 +393,7 @@ class Mongo extends Connection
$this->queryStr = 'db' . strstr($namespace, '.') . '.' . $this->queryStr;
}
$writeConcern = $options['writeConcern'] ?? null;
$writeConcern = $options['writeConcern'] ?? null;
$this->queryStartTime = microtime(true);
if ($session = $this->getSession()) {
@ -410,9 +414,9 @@ class Mongo extends Connection
if ($query->getOptions('cache')) {
// 清理缓存数据
$cacheItem = $this->parseCache($query, $query->getOptions('cache'));
$key = $cacheItem->getKey();
$tag = $cacheItem->getTag();
$cacheItem = $this->parseCache($query, $query->getOptions('cache'));
$key = $cacheItem->getKey();
$tag = $cacheItem->getTag();
if (isset($key) && $this->cache->has($key)) {
$this->cache->delete($key);
@ -440,7 +444,7 @@ class Mongo extends Connection
*
* @return array
*/
public function command(Command $command, string $dbName = '', ReadPreference $readPreference = null, $typeMap = null, bool $master = false): array
public function command(Command $command, string $dbName = '', ?ReadPreference $readPreference = null, $typeMap = null, bool $master = false): array
{
$this->initConnect($master);
$this->db->updateQueryTimes();
@ -590,11 +594,11 @@ class Mongo extends Connection
*/
public function close()
{
$this->mongo = null;
$this->cursor = null;
$this->linkRead = null;
$this->linkWrite = null;
$this->links = [];
$this->mongo = null;
$this->cursor = null;
$this->linkRead = null;
$this->linkWrite = null;
$this->links = [];
}
/**
@ -647,7 +651,8 @@ class Mongo extends Connection
if ($this->config['rw_separate']) {
// 主从式采用读写分离
if ($master) { // 主服务器写入
if ($master) {
// 主服务器写入
if ($this->config['is_replica_set']) {
return $this->replicaSetConnect();
} else {
@ -681,9 +686,9 @@ class Mongo extends Connection
*/
public function replicaSetConnect(): Manager
{
$this->dbName = $this->config['database'];
$this->typeMap = $this->config['type_map'];
$startTime = microtime(true);
$this->dbName = $this->config['database'];
$this->typeMap = $this->config['type_map'];
$startTime = microtime(true);
$this->config['params']['replicaSet'] = $this->config['database'];
@ -740,17 +745,17 @@ class Mongo extends Connection
}
// 生成bulk对象
$bulk = $this->builder->insert($query);
$writeResult = $this->mongoExecute($query, $bulk);
$result = $writeResult->getInsertedCount();
$bulk = $this->builder->insert($query);
$writeResult = $this->mongoExecute($query, $bulk);
$result = $writeResult->getInsertedCount();
if ($result) {
$data = $options['data'];
$lastInsId = $this->getLastInsID($query);
$data = $options['data'];
$lastInsId = $this->getLastInsID($query);
if ($lastInsId) {
$pk = $query->getPk();
$data[$pk] = $lastInsId;
$pk = $query->getPk();
$data[$pk] = $lastInsId;
}
$query->setOption('data', $data);
@ -773,7 +778,7 @@ class Mongo extends Connection
*
* @return mixed
*/
public function getLastInsID(BaseQuery $query, string $sequence = null)
public function getLastInsID(BaseQuery $query, ?string $sequence = null)
{
$id = $this->builder->getLastInsID();
@ -814,8 +819,8 @@ class Mongo extends Connection
}
// 生成bulkWrite对象
$bulk = $this->builder->insertAll($query, $dataSet);
$writeResult = $this->mongoExecute($query, $bulk);
$bulk = $this->builder->insertAll($query, $dataSet);
$writeResult = $this->mongoExecute($query, $bulk);
return $writeResult->getInsertedCount();
}
@ -839,9 +844,9 @@ class Mongo extends Connection
$query->parseOptions();
// 生成bulkWrite对象
$bulk = $this->builder->update($query);
$writeResult = $this->mongoExecute($query, $bulk);
$result = $writeResult->getModifiedCount();
$bulk = $this->builder->update($query);
$writeResult = $this->mongoExecute($query, $bulk);
$result = $writeResult->getModifiedCount();
if ($result) {
$this->db->trigger('after_update', $query);
@ -870,10 +875,10 @@ class Mongo extends Connection
$query->parseOptions();
// 生成bulkWrite对象
$bulk = $this->builder->delete($query);
$bulk = $this->builder->delete($query);
// 执行操作
$writeResult = $this->mongoExecute($query, $bulk);
$result = $writeResult->getDeletedCount();
$writeResult = $this->mongoExecute($query, $bulk);
$result = $writeResult->getDeletedCount();
if ($result) {
$this->db->trigger('after_delete', $query);
@ -960,7 +965,7 @@ class Mongo extends Connection
if (!empty($options['cache'])) {
$cacheItem = $this->parseCache($query, $options['cache']);
$key = $cacheItem->getKey();
$key = $cacheItem->getKey();
if ($this->cache->has($key)) {
return $this->cache->get($key);
@ -1003,7 +1008,7 @@ class Mongo extends Connection
*
* @return array
*/
public function column(BaseQuery $query, string|array $field, string $key = ''): array
public function column(BaseQuery $query, string | array $field, string $key = ''): array
{
$options = $query->parseOptions();
@ -1024,8 +1029,8 @@ class Mongo extends Connection
if (!empty($options['cache'])) {
// 判断查询缓存
$cacheItem = $this->parseCache($query, $options['cache']);
$key = $cacheItem->getKey();
$cacheItem = $this->parseCache($query, $options['cache']);
$key = $cacheItem->getKey();
if ($this->cache->has($key)) {
return $this->cache->get($key);
@ -1120,7 +1125,7 @@ class Mongo extends Connection
$this->commit();
return $result;
} catch (\Throwable $e) {
} catch (\Throwable $e) {
$this->rollback();
throw $e;
@ -1138,7 +1143,7 @@ class Mongo extends Connection
public function startTrans()
{
$this->initConnect(true);
$this->session_uuid = uniqid();
$this->session_uuid = uniqid();
$this->sessions[$this->session_uuid] = $this->getMongo()->startSession();
$this->sessions[$this->session_uuid]->startTransaction([]);
@ -1203,7 +1208,7 @@ class Mongo extends Connection
public function getSession()
{
return ($this->session_uuid && isset($this->sessions[$this->session_uuid]))
? $this->sessions[$this->session_uuid]
: null;
? $this->sessions[$this->session_uuid]
: null;
}
}

0
vendor/topthink/think-orm/src/db/connector/Mysql.php vendored Executable file → Normal file
View File

2
vendor/topthink/think-orm/src/db/connector/Oracle.php vendored Executable file → Normal file
View File

@ -107,7 +107,7 @@ class Oracle extends PDOConnection
*
* @return mixed
*/
public function getLastInsID(BaseQuery $query, string $sequence = null)
public function getLastInsID(BaseQuery $query, ?string $sequence = null)
{
if (!is_null($sequence)) {
$pdo = $this->linkID->query("select {$sequence}.currval as id from dual");

0
vendor/topthink/think-orm/src/db/connector/Pgsql.php vendored Executable file → Normal file
View File

0
vendor/topthink/think-orm/src/db/connector/Sqlite.php vendored Executable file → Normal file
View File

0
vendor/topthink/think-orm/src/db/connector/Sqlsrv.php vendored Executable file → Normal file
View File

0
vendor/topthink/think-orm/src/db/connector/pgsql.sql vendored Executable file → Normal file
View File

0
vendor/topthink/think-orm/src/db/connector/pgsql12.sql vendored Executable file → Normal file
View File

0
vendor/topthink/think-orm/src/db/exception/BindParamException.php vendored Executable file → Normal file
View File

View File

0
vendor/topthink/think-orm/src/db/exception/DbEventException.php vendored Executable file → Normal file
View File

0
vendor/topthink/think-orm/src/db/exception/DbException.php vendored Executable file → Normal file
View File

View File

0
vendor/topthink/think-orm/src/db/exception/ModelEventException.php vendored Executable file → Normal file
View File

View File

0
vendor/topthink/think-orm/src/db/exception/PDOException.php vendored Executable file → Normal file
View File