fix(vendor): 修复依赖升级导致的不兼容问题

This commit is contained in:
2025-12-08 14:03:47 +08:00
parent 0a9eadcdd0
commit 951836083e
50 changed files with 660 additions and 1010 deletions

View File

@@ -167,7 +167,7 @@ class Captcha
* @param bool $api
* @return Response
*/
public function create(string $config = null, bool $api = false): Response
public function create(string $config = null, bool $api = false)
{
$this->configure($config);
@@ -233,6 +233,14 @@ class Captcha
$content = ob_get_clean();
imagedestroy($this->im);
// api调用
if ($api) {
return [
'code' => implode('', $text),
'img' => 'data:image/png;base64,' . chunk_split(base64_encode($content))
];
}
return response($content, 200, ['Content-Length' => strlen($content)])->contentType('image/png');
}

View File

@@ -24,12 +24,6 @@ use Traversable;
/**
* 数据集管理类
*
* @template TKey of array-key
* @template-covariant TValue
*
* @implements ArrayAccess<TKey, TValue>
* @implements IteratorAggregate<TKey, TValue>
*/
class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Arrayable, Jsonable
{
@@ -39,19 +33,11 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
*/
protected $items = [];
/**
* 构造函数
* @param iterable<TKey, TValue>|Collection<TKey, TValue> $items 数据
*/
public function __construct($items = [])
{
$this->items = $this->convertToArray($items);
}
/**
* @param iterable<TKey, TValue>|Collection<TKey, TValue> $items
* @return static<TKey, TValue>
*/
public static function make($items = [])
{
return new static($items);
@@ -59,6 +45,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 是否为空
* @access public
* @return bool
*/
public function isEmpty(): bool
@@ -73,9 +60,6 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
}, $this->items);
}
/**
* @return array<TKey, TValue>
*/
public function all(): array
{
return $this->items;
@@ -84,6 +68,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 合并数组
*
* @access public
* @param mixed $items 数据
* @return static
*/
@@ -95,11 +80,12 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 按指定键整理数据
*
* @access public
* @param mixed $items 数据
* @param string|null $indexKey 键名
* @param string $indexKey 键名
* @return array
*/
public function dictionary($items = null, ?string &$indexKey = null)
public function dictionary($items = null, string &$indexKey = null)
{
if ($items instanceof self) {
$items = $items->all();
@@ -121,11 +107,12 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 比较数组,返回差集
*
* @access public
* @param mixed $items 数据
* @param string|null $indexKey 指定比较的键名
* @return static<TKey, TValue>
* @param string $indexKey 指定比较的键名
* @return static
*/
public function diff($items, ?string $indexKey = null)
public function diff($items, string $indexKey = null)
{
if ($this->isEmpty() || is_scalar($this->items[0])) {
return new static(array_diff($this->items, $this->convertToArray($items)));
@@ -148,11 +135,12 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 比较数组,返回交集
*
* @access public
* @param mixed $items 数据
* @param string|null $indexKey 指定比较的键名
* @return static<TKey, TValue>
* @param string $indexKey 指定比较的键名
* @return static
*/
public function intersect($items, ?string $indexKey = null)
public function intersect($items, string $indexKey = null)
{
if ($this->isEmpty() || is_scalar($this->items[0])) {
return new static(array_intersect($this->items, $this->convertToArray($items)));
@@ -175,7 +163,8 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 交换数组中的键和值
*
* @return static<TValue, TKey>
* @access public
* @return static
*/
public function flip()
{
@@ -185,7 +174,8 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 返回数组中所有的键名
*
* @return static<TKey, TValue>
* @access public
* @return static
*/
public function keys()
{
@@ -194,7 +184,8 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 返回数组中所有的值组成的新 Collection 实例
* @return static<int, TValue>
* @access public
* @return static
*/
public function values()
{
@@ -204,7 +195,8 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 删除数组的最后一个元素(出栈)
*
* @return TValue
* @access public
* @return mixed
*/
public function pop()
{
@@ -214,6 +206,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 通过使用用户自定义函数,以字符串返回数组
*
* @access public
* @param callable $callback 调用方法
* @param mixed $initial
* @return mixed
@@ -226,7 +219,8 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 以相反的顺序返回数组。
*
* @return static<TKey, TValue>
* @access public
* @return static
*/
public function reverse()
{
@@ -236,7 +230,8 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 删除数组中首个元素,并返回被删除元素的值
*
* @return TValue
* @access public
* @return mixed
*/
public function shift()
{
@@ -245,12 +240,12 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 在数组结尾插入一个元素
*
* @access public
* @param mixed $value 元素
* @param string|null $key KEY
* @param string $key KEY
* @return $this
*/
public function push($value, ?string $key = null)
public function push($value, string $key = null)
{
if (is_null($key)) {
$this->items[] = $value;
@@ -264,6 +259,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 把一个数组分割为新的数组块.
*
* @access public
* @param int $size 块大小
* @param bool $preserveKeys
* @return static
@@ -281,12 +277,12 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 在数组开头插入一个元素
*
* @access public
* @param mixed $value 元素
* @param string|null $key KEY
* @param string $key KEY
* @return $this
*/
public function unshift($value, ?string $key = null)
public function unshift($value, string $key = null)
{
if (is_null($key)) {
array_unshift($this->items, $value);
@@ -300,7 +296,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 给每个元素执行个回调
*
*
* @access public
* @param callable $callback 回调
* @return $this
*/
@@ -321,9 +317,9 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 用回调函数处理数组中的元素
*
* @access public
* @param callable|null $callback 回调
* @return static<TKey, TValue>
* @return static
*/
public function map(callable $callback)
{
@@ -332,11 +328,11 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 用回调函数过滤数组中的元素
*
* @access public
* @param callable|null $callback 回调
* @return static<TKey, TValue>
* @return static
*/
public function filter(?callable $callback = null)
public function filter(callable $callback = null)
{
if ($callback) {
return new static(array_filter($this->items, $callback));
@@ -347,11 +343,11 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 根据字段条件过滤数组中的元素
*
* @access public
* @param string $field 字段名
* @param mixed $operator 操作符
* @param mixed $value 数据
* @return static<TKey, TValue>
* @return static
*/
public function where(string $field, $operator, $value = null)
{
@@ -409,10 +405,10 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* LIKE过滤
*
* @access public
* @param string $field 字段名
* @param string $value 数据
* @return static<TKey, TValue>
* @return static
*/
public function whereLike(string $field, string $value)
{
@@ -421,10 +417,10 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* NOT LIKE过滤
*
* @access public
* @param string $field 字段名
* @param string $value 数据
* @return static<TKey, TValue>
* @return static
*/
public function whereNotLike(string $field, string $value)
{
@@ -433,10 +429,10 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* IN过滤
*
* @access public
* @param string $field 字段名
* @param array $value 数据
* @return static<TKey, TValue>
* @return static
*/
public function whereIn(string $field, array $value)
{
@@ -445,10 +441,10 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* NOT IN过滤
*
* @access public
* @param string $field 字段名
* @param array $value 数据
* @return static<TKey, TValue>
* @return static
*/
public function whereNotIn(string $field, array $value)
{
@@ -457,10 +453,10 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* BETWEEN 过滤
*
* @access public
* @param string $field 字段名
* @param mixed $value 数据
* @return static<TKey, TValue>
* @return static
*/
public function whereBetween(string $field, $value)
{
@@ -469,10 +465,10 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* NOT BETWEEN 过滤
*
* @access public
* @param string $field 字段名
* @param mixed $value 数据
* @return static<TKey, TValue>
* @return static
*/
public function whereNotBetween(string $field, $value)
{
@@ -481,12 +477,12 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 返回数据中指定的一列
*
* @access public
* @param string|null $columnKey 键名
* @param string|null $indexKey 作为索引值的列
* @return array
*/
public function column(?string $columnKey, ?string $indexKey = null)
public function column( ? string $columnKey, string $indexKey = null)
{
return array_column($this->items, $columnKey, $indexKey);
}
@@ -494,10 +490,11 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 对数组排序
*
* @access public
* @param callable|null $callback 回调
* @return static<TKey, TValue>
* @return static
*/
public function sort(?callable $callback = null)
public function sort(callable $callback = null)
{
$items = $this->items;
@@ -512,7 +509,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 指定字段排序
*
* @access public
* @param string $field 排序字段
* @param string $order 排序
* @return $this
@@ -523,14 +520,15 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
$fieldA = $a[$field] ?? null;
$fieldB = $b[$field] ?? null;
return 'desc' == strtolower($order) ? ($fieldB <=> $fieldA) : ($fieldA <=> $fieldB);
return 'desc' == strtolower($order) ? intval($fieldB > $fieldA) : intval($fieldA > $fieldB);
});
}
/**
* 将数组打乱
*
* @return static<TKey, TValue>
* @access public
* @return static
*/
public function shuffle()
{
@@ -544,11 +542,12 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 获取第一个单元数据
*
* @access public
* @param callable|null $callback
* @param null $default
* @return TValue
* @return mixed
*/
public function first(?callable $callback = null, $default = null)
public function first(callable $callback = null, $default = null)
{
return Arr::first($this->items, $callback, $default);
}
@@ -556,11 +555,12 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 获取最后一个单元数据
*
* @access public
* @param callable|null $callback
* @param null $default
* @return TValue
* @return mixed
*/
public function last(?callable $callback = null, $default = null)
public function last(callable $callback = null, $default = null)
{
return Arr::last($this->items, $callback, $default);
}
@@ -568,41 +568,30 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 截取数组
*
* @access public
* @param int $offset 起始位置
* @param int|null $length 截取长度
* @param int $length 截取长度
* @param bool $preserveKeys preserveKeys
* @return static<TKey, TValue>
* @return static
*/
public function slice(int $offset, ?int $length = null, bool $preserveKeys = false)
public function slice(int $offset, int $length = null, bool $preserveKeys = false)
{
return new static(array_slice($this->items, $offset, $length, $preserveKeys));
}
/**
* @param TKey $key
* @return bool
*/
// ArrayAccess
#[\ReturnTypeWillChange]
public function offsetExists($offset) : bool
{
return array_key_exists($offset, $this->items);
}
/**
* @param TKey $offset
* @return TValue
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return $this->items[$offset];
}
/**
* @param TKey|null $offset
* @param TValue $value
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
@@ -613,10 +602,6 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
}
}
/**
* @param TKey $offset
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
@@ -629,9 +614,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
return count($this->items);
}
/**
* @return ArrayIterator<TKey, TValue>
*/
//IteratorAggregate
#[\ReturnTypeWillChange]
public function getIterator(): Traversable
{
@@ -647,7 +630,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 转换当前数据集为JSON字符串
*
* @access public
* @param integer $options json参数
* @return string
*/
@@ -664,6 +647,7 @@ class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSeria
/**
* 转换成数组
*
* @access public
* @param mixed $items 数据
* @return array
*/

View File

@@ -16,15 +16,12 @@ if (!function_exists('throw_if')) {
/**
* 按条件抛异常
*
* @template TValue
* @template TException of \Throwable
* @param mixed $condition
* @param Throwable|string $exception
* @param array ...$parameters
* @return mixed
*
* @param TValue $condition
* @param TException|class-string<TException>|string $exception
* @param mixed ...$parameters
* @return TValue
*
* @throws TException
* @throws Throwable
*/
function throw_if($condition, $exception, ...$parameters)
{
@@ -40,15 +37,11 @@ if (!function_exists('throw_unless')) {
/**
* 按条件抛异常
*
* @template TValue
* @template TException of \Throwable
*
* @param TValue $condition
* @param TException|class-string<TException>|string $exception
* @param mixed ...$parameters
* @return TValue
*
* @throws TException
* @param mixed $condition
* @param Throwable|string $exception
* @param array ...$parameters
* @return mixed
* @throws Throwable
*/
function throw_unless($condition, $exception, ...$parameters)
{
@@ -64,11 +57,9 @@ if (!function_exists('tap')) {
/**
* 对一个值调用给定的闭包,然后返回该值
*
* @template TValue
*
* @param TValue $value
* @param (callable(TValue): mixed)|null $callback
* @return TValue
* @param mixed $value
* @param callable|null $callback
* @return mixed
*/
function tap($value, $callback = null)
{
@@ -86,10 +77,8 @@ if (!function_exists('value')) {
/**
* Return the default value of the given value.
*
* @template TValue
*
* @param TValue|\Closure(): TValue $value
* @return TValue
* @param mixed $value
* @return mixed
*/
function value($value)
{
@@ -288,30 +277,3 @@ if (!function_exists('class_uses_recursive')) {
return array_unique($results);
}
}
if (!function_exists('array_is_list')) {
/**
* 判断数组是否为list
*
* @param array $array 数据
* @return bool
*/
function array_is_list(array $array): bool
{
return array_values($array) === $array;
}
}
if (!function_exists('json_validate')) {
/**
* 判断是否为有效json数据
*
* @param string $string 数据
* @return bool
*/
function json_validate(string $string): bool
{
json_decode($string);
return json_last_error() === JSON_ERROR_NONE;
}
}

View File

@@ -32,9 +32,9 @@ class Arr
/**
* Add an element to an array using "dot" notation if it doesn't exist.
*
* @param array $array
* @param array $array
* @param string $key
* @param mixed $value
* @param mixed $value
* @return array
*/
public static function add($array, $key, $value)
@@ -110,7 +110,7 @@ class Arr
/**
* Flatten a multi-dimensional associative array with dots.
*
* @param array $array
* @param array $array
* @param string $prepend
* @return array
*/
@@ -132,7 +132,7 @@ class Arr
/**
* Get all of the given array except for a specified array of keys.
*
* @param array $array
* @param array $array
* @param array|string $keys
* @return array
*/
@@ -147,7 +147,7 @@ class Arr
* Determine if the given key exists in the provided array.
*
* @param \ArrayAccess|array $array
* @param string|int $key
* @param string|int $key
* @return bool
*/
public static function exists($array, $key)
@@ -162,12 +162,12 @@ class Arr
/**
* Return the first element in an array passing a given truth test.
*
* @param array $array
* @param array $array
* @param callable|null $callback
* @param mixed $default
* @param mixed $default
* @return mixed
*/
public static function first($array, ?callable $callback = null, $default = null)
public static function first($array, callable $callback = null, $default = null)
{
if (is_null($callback)) {
if (empty($array)) {
@@ -191,12 +191,12 @@ class Arr
/**
* Return the last element in an array passing a given truth test.
*
* @param array $array
* @param array $array
* @param callable|null $callback
* @param mixed $default
* @param mixed $default
* @return mixed
*/
public static function last($array, ?callable $callback = null, $default = null)
public static function last($array, callable $callback = null, $default = null)
{
if (is_null($callback)) {
return empty($array) ? value($default) : end($array);
@@ -209,7 +209,7 @@ class Arr
* Flatten a multi-dimensional array into a single level.
*
* @param array $array
* @param int $depth
* @param int $depth
* @return array
*/
public static function flatten($array, $depth = INF)
@@ -234,7 +234,7 @@ class Arr
/**
* Remove one or many array items from a given array using "dot" notation.
*
* @param array $array
* @param array $array
* @param array|string $keys
* @return void
*/
@@ -279,8 +279,8 @@ class Arr
* Get an item from an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string $key
* @param mixed $default
* @param string $key
* @param mixed $default
* @return mixed
*/
public static function get($array, $key, $default = null)
@@ -316,7 +316,7 @@ class Arr
* Check if an item or items exist in an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string|array $keys
* @param string|array $keys
* @return bool
*/
public static function has($array, $keys)
@@ -356,13 +356,15 @@ class Arr
*/
public static function isAssoc(array $array)
{
return !array_is_list($array);
$keys = array_keys($array);
return array_keys($keys) !== $keys;
}
/**
* Get a subset of the items from the given array.
*
* @param array $array
* @param array $array
* @param array|string $keys
* @return array
*/
@@ -374,8 +376,8 @@ class Arr
/**
* Pluck an array of values from an array.
*
* @param array $array
* @param string|array $value
* @param array $array
* @param string|array $value
* @param string|array|null $key
* @return array
*/
@@ -410,7 +412,7 @@ class Arr
/**
* Explode the "value" and "key" arguments passed to "pluck".
*
* @param string|array $value
* @param string|array $value
* @param string|array|null $key
* @return array
*/
@@ -445,9 +447,9 @@ class Arr
/**
* Get a value from the array, and remove it.
*
* @param array $array
* @param array $array
* @param string $key
* @param mixed $default
* @param mixed $default
* @return mixed
*/
public static function pull(&$array, $key, $default = null)
@@ -462,7 +464,7 @@ class Arr
/**
* Get one or a specified number of random values from an array.
*
* @param array $array
* @param array $array
* @param int|null $number
* @return mixed
*
@@ -504,9 +506,9 @@ class Arr
*
* If no key is given to the method, the entire array will be replaced.
*
* @param array $array
* @param array $array
* @param string $key
* @param mixed $value
* @param mixed $value
* @return array
*/
public static function set(&$array, $key, $value)
@@ -538,7 +540,7 @@ class Arr
/**
* Shuffle the given array and return the result.
*
* @param array $array
* @param array $array
* @param int|null $seed
* @return array
*/
@@ -560,7 +562,7 @@ class Arr
/**
* Sort the array using the given callback or "dot" notation.
*
* @param array $array
* @param array $array
* @param callable|string|null $callback
* @return array
*/
@@ -606,7 +608,7 @@ class Arr
/**
* Filter the array using the given callback.
*
* @param array $array
* @param array $array
* @param callable $callback
* @return array
*/
@@ -629,41 +631,4 @@ class Arr
return is_array($value) ? $value : [$value];
}
/**
* Recursively merge arrays.
* If the value is an associative array, it will be merged recursively.
* If the value is an indexed array, it will be replaced entirely.
*
* @param array ...$arrays
* @return array
*/
public static function mergeDeep(array ...$arrays): array
{
$result = [];
foreach ($arrays as $array) {
foreach ($array as $key => $value) {
if (isset($result[$key]) && is_array($result[$key]) && is_array($value)) {
// 只有当两个数组都是关联数组时才递归合并
if (self::isAssoc($result[$key]) && self::isAssoc($value)) {
$result[$key] = self::mergeDeep(
$result[$key],
$value
);
} else {
// 如果任一数组是索引数组,则直接覆盖
$result[$key] = $value;
}
} else {
$result[$key] = $value;
}
}
}
return $result;
}
public static function flatMap(callable $fn, array $array): array
{
return array_merge(...array_map($fn, $array));
}
}
}

View File

@@ -80,7 +80,7 @@ class Str
* @param string $addChars
* @return string
*/
public static function random(int $length = 6, ?int $type = null, string $addChars = ''): string
public static function random(int $length = 6, int $type = null, string $addChars = ''): string
{
$str = '';
switch ($type) {
@@ -158,7 +158,7 @@ class Str
* @param int|null $length
* @return string
*/
public static function substr(string $string, int $start, ?int $length = null): string
public static function substr(string $string, int $start, int $length = null): string
{
return mb_substr($string, $start, $length, 'UTF-8');
}

View File

@@ -55,7 +55,7 @@ class ArrTest extends TestCase
public function testDivide()
{
[$keys, $values] = Arr::divide(['name' => 'ThinkPHP']);
list($keys, $values) = Arr::divide(['name' => 'ThinkPHP']);
$this->assertSame(['name'], $keys);
$this->assertSame(['ThinkPHP'], $values);
}
@@ -109,7 +109,7 @@ class ArrTest extends TestCase
public function testLast()
{
$array = [100, 200, 300];
$last = Arr::last($array, function ($value) {
$last = Arr::last($array, function ($value) {
return $value < 250;
});
$this->assertSame(200, $last);
@@ -234,17 +234,17 @@ class ArrTest extends TestCase
public function testPull()
{
$array = ['name' => 'ThinkPHP', 'price' => 100];
$name = Arr::pull($array, 'name');
$name = Arr::pull($array, 'name');
$this->assertSame('ThinkPHP', $name);
$this->assertSame(['price' => 100], $array);
// Only works on first level keys
$array = ['i@example.com' => 'Joe', 'jack@localhost' => 'Jane'];
$name = Arr::pull($array, 'i@example.com');
$name = Arr::pull($array, 'i@example.com');
$this->assertSame('Joe', $name);
$this->assertSame(['jack@localhost' => 'Jane'], $array);
// Does not work for nested keys
$array = ['emails' => ['i@example.com' => 'Joe', 'jack@localhost' => 'Jane']];
$name = Arr::pull($array, 'emails.i@example.com');
$name = Arr::pull($array, 'emails.i@example.com');
$this->assertNull($name);
$this->assertSame(['emails' => ['i@example.com' => 'Joe', 'jack@localhost' => 'Jane']], $array);
}
@@ -331,42 +331,12 @@ class ArrTest extends TestCase
public function testWrap()
{
$string = 'a';
$array = ['a'];
$object = new stdClass();
$string = 'a';
$array = ['a'];
$object = new stdClass();
$object->value = 'a';
$this->assertSame(['a'], Arr::wrap($string));
$this->assertSame($array, Arr::wrap($array));
$this->assertSame([$object], Arr::wrap($object));
}
public function testMergeDeep()
{
$this->assertSame(
[
'a' => [
'c' => [2],
'e' => 5,
'f' => 4,
],
'x' => 3,
],
Arr::mergeDeep(
[
'a' => [
'c' => [1],
'e' => 5,
],
'x' => 4,
],
[
'a' => [
'c' => [2],
'f' => 4,
],
'x' => 3,
]
)
);
}
}

View File

@@ -1,32 +1,33 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace think\app;
use think\Service as BaseService;
class Service extends BaseService
{
public function boot()
{
$this->app->event->listen('HttpRun', function () {
$this->app->middleware->add(MultiApp::class);
});
$this->commands([
'build' => command\Build::class,
'clear' => command\Clear::class,
]);
$this->app->bind([
'think\route\Url' => Url::class,
]);
}
}
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace think\app;
use think\Service as BaseService;
class Service extends BaseService
{
public function boot()
{
$this->app->event->listen('HttpRun', function () {
$this->app->middleware->add(MultiApp::class);
});
$this->commands([
'build' => command\Build::class,
'clear' => command\Clear::class,
]);
$this->app->bind([
'think\route\Url' => Url::class,
]);
}
}

View File

@@ -52,6 +52,12 @@ class DbManager
*/
protected $listen = [];
/**
* SQL日志
* @var array
*/
protected $dbLog = [];
/**
* 查询次数
* @var int
@@ -161,6 +167,8 @@ class DbManager
{
if ($this->log) {
$this->log->log($type, $log);
} else {
$this->dbLog[$type][] = $log;
}
}
@@ -172,7 +180,12 @@ class DbManager
*/
public function getDbLog(bool $clear = false): array
{
return [];
$logs = $this->dbLog;
if ($clear) {
$this->dbLog = [];
}
return $logs;
}
/**
@@ -279,17 +292,16 @@ class DbManager
/**
* 更新查询次数
* @deprecated
* @access public
* @return void
*/
public function updateQueryTimes(): void
{
$this->queryTimes++;
}
/**
* 重置查询次数
* @deprecated
* @access public
* @return void
*/
@@ -300,7 +312,6 @@ class DbManager
/**
* 获得查询次数
* @deprecated
* @access public
* @return integer
*/
@@ -330,16 +341,6 @@ class DbManager
return $this->listen;
}
/**
* 获取所有连接实列
* @access public
* @return array
*/
public function getInstance(): array
{
return $this->instance;
}
/**
* 注册回调方法
* @access public

View File

@@ -121,12 +121,6 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
*/
private $lazySave = false;
/**
* 缓存自动更新标识
* @var bool|string
*/
protected $cacheKey = false;
/**
* Db对象
* @var DbManager
@@ -341,18 +335,6 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
return $this;
}
/**
* 设置当前查询的自动缓存标识
* @access public
* @param string|bool $key 缓存标识
* @return $this
*/
public function setCacheKey($key)
{
$this->cacheKey = $key;
return $this;
}
/**
* 获取当前模型的数据表后缀
* @access public
@@ -659,7 +641,7 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
$result = $db->where($where)
->strict(false)
->cache($this->cacheKey)
->cache(true)
->setOption('key', $this->key)
->field($allowFields)
->update($data);
@@ -787,20 +769,16 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
$pk = $this->getPk();
if (is_string($pk) && $replace) {
$auto = true;
}
$result = [];
$suffix = $this->getSuffix();
foreach ($dataSet as $key => $data) {
if ($replace) {
$exists = true;
foreach ((array) $pk as $field) {
if (!isset($data[$field])) {
$exists = false;
}
}
}
if ($replace && !empty($exists)) {
if ($this->exists || (!empty($auto) && isset($data[$pk]))) {
$result[$key] = static::update($data, [], [], $suffix);
} else {
$result[$key] = static::create($data, $this->field, $this->replace, $suffix);
@@ -831,7 +809,7 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
$db->transaction(function () use ($where, $db) {
// 删除当前模型数据
$db->where($where)->cache($this->cacheKey)->delete();
$db->where($where)->delete();
// 关联删除
if (!empty($this->relationWrite)) {

View File

@@ -377,19 +377,6 @@ abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, J
return $this->items;
}
/**
* 设置数据集
*
* @param Collection $items
* @return $this
*/
public function setCollection(Collection $items)
{
$this->items = $items;
return $this;
}
public function isEmpty(): bool
{
return $this->items->isEmpty();

View File

@@ -770,9 +770,10 @@ abstract class BaseQuery
* @param mixed $key 缓存key
* @param integer|\DateTime $expire 缓存有效期
* @param string|array $tag 缓存标签
* @param bool $always 始终缓存
* @return $this
*/
public function cache($key = true, $expire = null, $tag = null)
public function cache($key = true, $expire = null, $tag = null, bool $always = false)
{
if (false === $key || !$this->getConnection()->getCache()) {
return $this;
@@ -783,7 +784,8 @@ abstract class BaseQuery
$key = true;
}
$this->options['cache'] = [$key, $expire, $tag ?: $this->getTable()];
$this->options['cache'] = [$key, $expire, $tag];
$this->options['cache_always'] = $always;
return $this;
}
@@ -798,23 +800,7 @@ abstract class BaseQuery
*/
public function cacheAlways($key = true, $expire = null, $tag = null)
{
$this->options['cache_always'] = true;
return $this->cache($key, $expire, $tag);
}
/**
* 强制更新缓存
*
* @param mixed $key 缓存key
* @param int|\DateTime $expire 缓存有效期
* @param string|array $tag 缓存标签
*
* @return $this
*/
public function cacheForce($key = true, $expire = null, $tag = null)
{
$this->options['force_cache'] = true;
return $this->cache($key, $expire, $tag);
return $this->cache($key, $expire, $tag, true);
}
/**
@@ -1040,23 +1026,6 @@ abstract class BaseQuery
return $this->connection->insertAll($this, $dataSet, $limit);
}
/**
* 批量插入记录
* @access public
* @param array $keys 键值
* @param array $values 数据
* @param integer $limit 每次写入数据限制
* @return integer
*/
public function insertAllByKeys(array $keys, array $values, int $limit = 0): int
{
if (empty($limit) && !empty($this->options['limit']) && is_numeric($this->options['limit'])) {
$limit = (int) $this->options['limit'];
}
return $this->connection->insertAllByKeys($this, $keys, $values, $limit);
}
/**
* 通过Select方式插入记录
* @access public

View File

@@ -158,8 +158,7 @@ abstract class Builder
if (false !== strpos($key, '->')) {
[$key, $name] = explode('->', $key, 2);
$item = $this->parseKey($query, $key);
$result[$item . '->' . $name] = 'json_set(' . $item . ', \'$.' . $name . '\', ' . $this->parseDataBind($query, $key . '->' . $name, $val, $bind) . ')';
$result[$item] = 'json_set(' . $item . ', \'$.' . $name . '\', ' . $this->parseDataBind($query, $key . '->' . $name, $val, $bind) . ')';
} elseif (false === strpos($key, '.') && !in_array($key, $fields, true)) {
if ($options['strict']) {
throw new Exception('fields not exists:[' . $key . ']');
@@ -177,11 +176,7 @@ abstract class Builder
}
} elseif (is_scalar($val)) {
// 过滤非标量数据
if (!$query->isAutoBind() && PDO::PARAM_STR == $bind[$key]) {
$val = '\'' . $val . '\'';
}
$result[$item] = !$query->isAutoBind() ? $val : $this->parseDataBind($query, $key, $val, $bind);
$result[$item] = $this->parseDataBind($query, $key, $val, $bind);
}
}
@@ -766,22 +761,17 @@ abstract class Builder
if (count($value) === 0) {
return 'IN' == $exp ? '0 = 1' : '1 = 1';
}
$array = [];
if ($query->isAutoBind()) {
$array = [];
foreach ($value as $v) {
$name = $query->bindValue($v, $bindType);
$array[] = ':' . $name;
}
$value = implode(',', $array);
} elseif (PDO::PARAM_STR == $bindType) {
$value = '\'' . implode('\',\'', $value) . '\'';
} else {
$value = implode(',', $value);
foreach ($value as $v) {
$name = $query->bindValue($v, $bindType);
$array[] = ':' . $name;
}
if (false === strpos($value, ',')) {
return $key . ('IN' == $exp ? ' = ' : ' <> ') . $value;
if (count($array) == 1) {
return $key . ('IN' == $exp ? ' = ' : ' <> ') . $array[0];
} else {
$value = implode(',', $array);
}
}
@@ -1149,8 +1139,7 @@ abstract class Builder
$this->parseComment($query, $options['comment']),
$this->parseForce($query, $options['force']),
],
$this->selectSql
);
$this->selectSql);
}
/**
@@ -1182,8 +1171,7 @@ abstract class Builder
implode(' , ', $values),
$this->parseComment($query, $options['comment']),
],
$this->insertSql
);
$this->insertSql);
}
/**
@@ -1234,57 +1222,9 @@ abstract class Builder
implode(' UNION ALL ', $values),
$this->parseComment($query, $options['comment']),
],
$this->insertAllSql
);
$this->insertAllSql);
}
/**
* 生成insertall SQL
* @access public
* @param Query $query 查询对象
* @param array $keys 字段名
* @param array $datas 数据
* @return string
*/
public function insertAllByKeys(Query $query, array $keys, array $datas): string
{
$options = $query->getOptions();
// 获取绑定信息
$bind = $query->getFieldsBindType();
$fields = [];
$values = [];
foreach ($keys as $field) {
$fields[] = $this->parseKey($query, $field);
}
foreach ($datas as $data) {
foreach ($data as $key => &$val) {
if (!$query->isAutoBind()) {
$val = PDO::PARAM_STR == $bind[$keys[$key]] ? '\'' . $val . '\'' : $val;
} else {
$val = $this->parseDataBind($query, $keys[$key], $val, $bind);
}
}
$values[] = 'SELECT ' . implode(',', $data);
}
return str_replace(
['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'],
[
!empty($options['replace']) ? 'REPLACE' : 'INSERT',
$this->parseTable($query, $options['table']),
$this->parseExtra($query, $options['extra']),
implode(' , ', $fields),
implode(' UNION ALL ', $values),
$this->parseComment($query, $options['comment']),
],
$this->insertAllSql
);
}
/**
* 生成slect insert SQL
* @access public
@@ -1336,8 +1276,7 @@ abstract class Builder
$this->parseLock($query, $options['lock']),
$this->parseComment($query, $options['comment']),
],
$this->updateSql
);
$this->updateSql);
}
/**
@@ -1363,7 +1302,6 @@ abstract class Builder
$this->parseLock($query, $options['lock']),
$this->parseComment($query, $options['comment']),
],
$this->deleteSql
);
$this->deleteSql);
}
}

View File

@@ -8,7 +8,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db;

View File

@@ -309,7 +309,7 @@ class Fetch
$this->query->setOption('soft_delete', null);
$this->query->setOption('data', [$field => $condition]);
// 生成删除SQL语句
$sql = $this->builder->update($this->query);
$sql = $this->builder->delete($this->query);
return $this->fetch($sql);
}
}

View File

@@ -8,7 +8,7 @@
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
declare(strict_types=1);
declare (strict_types = 1);
namespace think\db;
@@ -81,8 +81,6 @@ abstract class PDOConnection extends Connection
'break_reconnect' => false,
// 断线标识字符串
'break_match_str' => [],
// 自动参数绑定
'auto_param_bind' => true,
];
/**
@@ -354,13 +352,15 @@ abstract class PDOConnection extends Connection
if (!isset($this->info[$schema]) || $force) {
// 读取字段缓存
$cacheKey = $this->getSchemaCacheKey($schema);
if ($this->config['fields_cache'] && !empty($this->cache) && !$force) {
$cacheField = $this->config['fields_cache'] && !empty($this->cache);
if ($cacheField && !$force) {
$info = $this->cache->get($cacheKey);
}
if (empty($info)) {
$info = $this->getTableFieldsInfo($tableName);
if (!empty($this->cache) && ($this->config['fields_cache'] || $force)) {
if ($cacheField) {
$this->cache->set($cacheKey, $info);
}
}
@@ -622,14 +622,15 @@ abstract class PDOConnection extends Connection
* @access public
* @param BaseQuery $query 查询对象
* @param string $sql sql指令
* @param array $bind 参数绑定
* @param Model|null $model 模型对象实例
* @param null $condition 查询条件
* @return \Generator
* @throws DbException
*/
public function getCursor(BaseQuery $query, string $sql, $model = null, $condition = null)
public function getCursor(BaseQuery $query, string $sql, array $bind = [], $model = null, $condition = null)
{
$this->queryPDOStatement($query, $sql);
$this->queryPDOStatement($query, $sql, $bind);
// 返回结果集
while ($result = $this->PDOStatement->fetch($this->fetchType)) {
@@ -652,7 +653,7 @@ abstract class PDOConnection extends Connection
*/
public function query(string $sql, array $bind = [], bool $master = false): array
{
return $this->pdoQuery($this->newQuery()->bind($bind), $sql, $master);
return $this->pdoQuery($this->newQuery(), $sql, $bind, $master);
}
/**
@@ -665,7 +666,7 @@ abstract class PDOConnection extends Connection
*/
public function execute(string $sql, array $bind = []): int
{
return $this->pdoExecute($this->newQuery()->bind($bind), $sql, true);
return $this->pdoExecute($this->newQuery(), $sql, $bind, true);
}
/**
@@ -673,27 +674,25 @@ abstract class PDOConnection extends Connection
* @access protected
* @param BaseQuery $query 查询对象
* @param mixed $sql sql指令
* @param array $bind 参数绑定
* @param bool $master 主库读取
* @return array
* @throws DbException
*/
protected function pdoQuery(BaseQuery $query, $sql, bool $master = null): array
protected function pdoQuery(BaseQuery $query, $sql, array $bind = [], bool $master = null): array
{
// 分析查询表达式
$query->parseOptions();
$bind = $query->getBind();
if ($query->getOptions('cache')) {
// 检查查询缓存
$cacheItem = $this->parseCache($query, $query->getOptions('cache'));
if (!$query->getOptions('force_cache')) {
$key = $cacheItem->getKey();
$key = $cacheItem->getKey();
$data = $this->cache->get($key);
$data = $this->cache->get($key);
if (null !== $data) {
return $data;
}
if (null !== $data) {
return $data;
}
}
@@ -731,10 +730,11 @@ abstract class PDOConnection extends Connection
*/
public function pdo(BaseQuery $query): PDOStatement
{
$bind = $query->getBind();
// 生成查询SQL
$sql = $this->builder->select($query);
return $this->queryPDOStatement($query, $sql);
return $this->queryPDOStatement($query, $sql, $bind);
}
/**
@@ -806,17 +806,18 @@ abstract class PDOConnection extends Connection
* @access protected
* @param BaseQuery $query 查询对象
* @param string $sql sql指令
* @param array $bind 参数绑定
* @param bool $origin 是否原生查询
* @return int
* @throws DbException
*/
protected function pdoExecute(BaseQuery $query, string $sql, bool $origin = false): int
protected function pdoExecute(BaseQuery $query, string $sql, array $bind = [], bool $origin = false): int
{
if ($origin) {
$query->parseOptions();
}
$this->queryPDOStatement($query->master(true), $sql);
$this->queryPDOStatement($query->master(true), $sql, $bind);
if (!$origin && !empty($this->config['deploy']) && !empty($this->config['read_master'])) {
$this->readMaster = true;
@@ -843,13 +844,13 @@ abstract class PDOConnection extends Connection
/**
* @param BaseQuery $query
* @param string $sql
* @param array $bind
* @return PDOStatement
* @throws DbException
*/
protected function queryPDOStatement(BaseQuery $query, string $sql): PDOStatement
protected function queryPDOStatement(BaseQuery $query, string $sql, array $bind = []): PDOStatement
{
$options = $query->getOptions();
$bind = $query->getBind();
$master = !empty($options['master']) ? true : false;
$procedure = !empty($options['procedure']) ? true : in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);
@@ -897,7 +898,7 @@ abstract class PDOConnection extends Connection
$condition = $options['where']['AND'] ?? null;
// 执行查询操作
return $this->getCursor($query, $sql, $query->getModel(), $condition);
return $this->getCursor($query, $sql, $query->getBind(), $query->getModel(), $condition);
}
/**
@@ -937,7 +938,7 @@ abstract class PDOConnection extends Connection
$sql = $this->builder->insert($query);
// 执行操作
$result = '' == $sql ? 0 : $this->pdoExecute($query, $sql);
$result = '' == $sql ? 0 : $this->pdoExecute($query, $sql, $query->getBind());
if ($result) {
$sequence = $options['sequence'] ?? null;
@@ -976,12 +977,13 @@ abstract class PDOConnection extends Connection
*/
public function insertAll(BaseQuery $query, array $dataSet = [], int $limit = 0): int
{
$query->parseOptions();
if (!is_array(reset($dataSet))) {
return 0;
}
$options = $query->parseOptions();
$replace = !empty($options['replace']);
if (0 === $limit && count($dataSet) >= 5000) {
$limit = 1000;
}
@@ -995,8 +997,8 @@ abstract class PDOConnection extends Connection
$count = 0;
foreach ($array as $item) {
$sql = $this->builder->insertAll($query, $item);
$count += $this->pdoExecute($query, $sql);
$sql = $this->builder->insertAll($query, $item, $replace);
$count += $this->pdoExecute($query, $sql, $query->getBind());
}
// 提交事务
@@ -1009,56 +1011,9 @@ abstract class PDOConnection extends Connection
return $count;
}
$sql = $this->builder->insertAll($query, $dataSet);
$sql = $this->builder->insertAll($query, $dataSet, $replace);
return $this->pdoExecute($query, $sql);
}
/**
* 批量插入记录
* @access public
* @param BaseQuery $query 查询对象
* @param array $keys 键值
* @param array $values 数据
* @param integer $limit 每次写入数据限制
* @return integer
* @throws \Exception
* @throws \Throwable
*/
public function insertAllByKeys(BaseQuery $query, array $keys, array $values, int $limit = 0): int
{
$query->parseOptions();
if (0 === $limit && count($values) >= 5000) {
$limit = 1000;
}
if ($limit) {
// 分批写入 自动启动事务支持
$this->startTrans();
try {
$array = array_chunk($values, $limit, true);
$count = 0;
foreach ($array as $item) {
$sql = $this->builder->insertAllByKeys($query, $keys, $item);
$count += $this->pdoExecute($query, $sql);
}
// 提交事务
$this->commit();
} catch (\Exception | \Throwable $e) {
$this->rollback();
throw $e;
}
return $count;
}
$sql = $this->builder->insertAllByKeys($query, $keys, $values);
return $this->pdoExecute($query, $sql);
return $this->pdoExecute($query, $sql, $query->getBind());
}
/**
@@ -1077,7 +1032,7 @@ abstract class PDOConnection extends Connection
$sql = $this->builder->selectInsert($query, $fields, $table);
return $this->pdoExecute($query, $sql);
return $this->pdoExecute($query, $sql, $query->getBind());
}
/**
@@ -1095,7 +1050,7 @@ abstract class PDOConnection extends Connection
$sql = $this->builder->update($query);
// 执行操作
$result = '' == $sql ? 0 : $this->pdoExecute($query, $sql);
$result = '' == $sql ? 0 : $this->pdoExecute($query, $sql, $query->getBind());
if ($result) {
$this->db->trigger('after_update', $query);
@@ -1120,7 +1075,7 @@ abstract class PDOConnection extends Connection
$sql = $this->builder->delete($query);
// 执行操作
$result = $this->pdoExecute($query, $sql);
$result = $this->pdoExecute($query, $sql, $query->getBind());
if ($result) {
$this->db->trigger('after_delete', $query);
@@ -1154,13 +1109,10 @@ abstract class PDOConnection extends Connection
if (!empty($options['cache'])) {
$cacheItem = $this->parseCache($query, $options['cache'], 'value');
$key = $cacheItem->getKey();
if (!$query->getOptions('force_cache')) {
$key = $cacheItem->getKey();
if ($this->cache->has($key)) {
return $this->cache->get($key);
}
if ($this->cache->has($key)) {
return $this->cache->get($key);
}
}
@@ -1233,13 +1185,13 @@ abstract class PDOConnection extends Connection
$key = null;
}
if (is_string($column)) {
$column = trim($column);
if (\is_string($column)) {
$column = \trim($column);
if ('*' !== $column) {
$column = array_map('trim', explode(',', $column));
$column = \array_map('\trim', \explode(',', $column));
}
} elseif (is_array($column)) {
if (in_array('*', $column)) {
} elseif (\is_array($column)) {
if (\in_array('*', $column)) {
$column = '*';
}
} else {
@@ -1247,7 +1199,7 @@ abstract class PDOConnection extends Connection
}
$field = $column;
if ('*' !== $column && $key && !in_array($key, $column)) {
if ('*' !== $column && $key && !\in_array($key, $column)) {
$field[] = $key;
}
@@ -1256,12 +1208,10 @@ abstract class PDOConnection extends Connection
if (!empty($options['cache'])) {
// 判断查询缓存
$cacheItem = $this->parseCache($query, $options['cache'], 'column');
if (!$query->getOptions('force_cache')) {
$name = $cacheItem->getKey();
$name = $cacheItem->getKey();
if ($this->cache->has($name)) {
return $this->cache->get($name);
}
if ($this->cache->has($name)) {
return $this->cache->get($name);
}
}
@@ -1284,23 +1234,19 @@ abstract class PDOConnection extends Connection
if (empty($resultSet)) {
$result = [];
} elseif ('*' !== $column && count($column) === 1) {
$column = array_shift($column);
if (strpos($column, ' ')) {
$column = substr(strrchr(trim($column), ' '), 1);
} elseif ('*' !== $column && \count($column) === 1) {
$column = \array_shift($column);
if (\strpos($column, ' ')) {
$column = \substr(\strrchr(\trim($column), ' '), 1);
}
if (strpos($column, '.')) {
[$alias, $column] = explode('.', $column);
if (\strpos($column, '.')) {
[$alias, $column] = \explode('.', $column);
}
if (strpos($column, '->')) {
$column = $this->builder->parseKey($query, $column);
}
$result = array_column($resultSet, $column, $key);
$result = \array_column($resultSet, $column, $key);
} elseif ($key) {
$result = array_column($resultSet, null, $key);
$result = \array_column($resultSet, null, $key);
} else {
$result = $resultSet;
}
@@ -1335,8 +1281,8 @@ abstract class PDOConnection extends Connection
// 判断占位符
$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) :
substr_replace($sql, $value, strpos($sql, ':' . $key), strlen(':' . $key));
}
return rtrim($sql);
@@ -1595,16 +1541,17 @@ abstract class PDOConnection extends Connection
* @access public
* @param BaseQuery $query 查询对象
* @param array $sqlArray SQL批处理指令
* @param array $bind 参数绑定
* @return bool
*/
public function batchQuery(BaseQuery $query, array $sqlArray = []): bool
public function batchQuery(BaseQuery $query, array $sqlArray = [], array $bind = []): bool
{
// 自动启动事务支持
$this->startTrans();
try {
foreach ($sqlArray as $sql) {
$this->pdoExecute($query, $sql);
$this->pdoExecute($query, $sql, $bind);
}
// 提交事务
$this->commit();
@@ -1697,7 +1644,7 @@ abstract class PDOConnection extends Connection
$pk = $query->getAutoInc();
if ($pk) {
$type = $this->getFieldsBind($query->getTable())[$pk];
$type = $this->getFieldBindType($pk);
if (PDO::PARAM_INT == $type) {
$insertId = (int) $insertId;
@@ -1811,17 +1758,6 @@ abstract class PDOConnection extends Connection
return $this->connect($dbConfig, $r, $r == $m ? false : $dbMaster);
}
/**
* 获取数据库的唯一标识
* @access public
* @param string $suffix 标识后缀
* @return string
*/
public function getUniqueXid(string $suffix = ''): string
{
return $this->config['hostname'] . '_' . $this->config['database'] . $suffix;
}
/**
* 执行数据库Xa事务
* @access public
@@ -1847,7 +1783,7 @@ abstract class PDOConnection extends Connection
$dbs[$key] = $db;
}
$db->startTransXa($db->getUniqueXid('_' . $xid) );
$db->startTransXa($xid);
}
try {
@@ -1857,17 +1793,17 @@ abstract class PDOConnection extends Connection
}
foreach ($dbs as $db) {
$db->prepareXa($db->getUniqueXid('_' . $xid));
$db->prepareXa($xid);
}
foreach ($dbs as $db) {
$db->commitXa($db->getUniqueXid('_' . $xid) );
$db->commitXa($xid);
}
return $result;
} catch (\Exception | \Throwable $e) {
foreach ($dbs as $db) {
$db->rollbackXa($db->getUniqueXid('_' . $xid) );
$db->rollbackXa($xid);
}
throw $e;
}
@@ -1880,8 +1816,7 @@ abstract class PDOConnection extends Connection
* @return void
*/
public function startTransXa(string $xid): void
{
}
{}
/**
* 预编译XA事务
@@ -1890,8 +1825,7 @@ abstract class PDOConnection extends Connection
* @return void
*/
public function prepareXa(string $xid): void
{
}
{}
/**
* 提交XA事务
@@ -1900,8 +1834,7 @@ abstract class PDOConnection extends Connection
* @return void
*/
public function commitXa(string $xid): void
{
}
{}
/**
* 回滚XA事务
@@ -1910,6 +1843,5 @@ abstract class PDOConnection extends Connection
* @return void
*/
public function rollbackXa(string $xid): void
{
}
{}
}

View File

@@ -13,6 +13,7 @@ declare (strict_types = 1);
namespace think\db;
use PDOStatement;
use think\helper\Str;
/**
* PDO数据查询类

View File

@@ -111,6 +111,8 @@ class Mongo
$result[$item] = $val;
} elseif (isset($val[0]) && 'exp' == $val[0]) {
$result[$item] = $val[1];
} elseif (is_null($val)) {
$result[$item] = 'NULL';
} else {
$result[$item] = $this->parseValue($query, $val, $key);
}

View File

@@ -12,7 +12,6 @@ declare (strict_types = 1);
namespace think\db\builder;
use PDO;
use think\db\Builder;
use think\db\exception\DbException as Exception;
use think\db\Query;
@@ -28,7 +27,7 @@ class Mysql extends Builder
* @var array
*/
protected $parser = [
'parseCompare' => ['=', '!=', '<>', '>', '>=', '<', '<='],
'parseCompare' => ['=', '<>', '>', '>=', '<', '<='],
'parseLike' => ['LIKE', 'NOT LIKE'],
'parseBetween' => ['NOT BETWEEN', 'BETWEEN'],
'parseIn' => ['NOT IN', 'IN'],
@@ -102,8 +101,7 @@ class Mysql extends Builder
$this->parseComment($query, $options['comment']),
$this->parseForce($query, $options['force']),
],
$this->selectSql
);
$this->selectSql);
}
/**
@@ -138,8 +136,7 @@ class Mysql extends Builder
$this->parseDuplicate($query, $options['duplicate']),
$this->parseComment($query, $options['comment']),
],
$this->insertSql
);
$this->insertSql);
}
/**
@@ -147,9 +144,10 @@ class Mysql extends Builder
* @access public
* @param Query $query 查询对象
* @param array $dataSet 数据集
* @param bool $replace 是否replace
* @return string
*/
public function insertAll(Query $query, array $dataSet): string
public function insertAll(Query $query, array $dataSet, bool $replace = false): string
{
$options = $query->getOptions();
@@ -183,7 +181,7 @@ class Mysql extends Builder
return str_replace(
['%INSERT%', '%EXTRA%', '%TABLE%', '%PARTITION%', '%FIELD%', '%DATA%', '%DUPLICATE%', '%COMMENT%'],
[
!empty($options['replace']) ? 'REPLACE' : 'INSERT',
$replace ? 'REPLACE' : 'INSERT',
$this->parseExtra($query, $options['extra']),
$this->parseTable($query, $options['table']),
$this->parsePartition($query, $options['partition']),
@@ -192,56 +190,7 @@ class Mysql extends Builder
$this->parseDuplicate($query, $options['duplicate']),
$this->parseComment($query, $options['comment']),
],
$this->insertAllSql
);
}
/**
* 生成insertall SQL
* @access public
* @param Query $query 查询对象
* @param array $keys 键值
* @param array $values 数据
* @return string
*/
public function insertAllByKeys(Query $query, array $keys, array $datas): string
{
$options = $query->getOptions();
// 获取绑定信息
$bind = $query->getFieldsBindType();
$fields = [];
$values = [];
foreach ($keys as $field) {
$fields[] = $this->parseKey($query, $field);
}
foreach ($datas as $data) {
foreach ($data as $key => &$val) {
if (!$query->isAutoBind()) {
$val = PDO::PARAM_STR == $bind[$keys[$key]] ? '\'' . $val . '\'' : $val;
} else {
$val = $this->parseDataBind($query, $keys[$key], $val, $bind);
}
}
$values[] = '( ' . implode(',', $data) . ' )';
}
return str_replace(
['%INSERT%', '%EXTRA%', '%TABLE%', '%PARTITION%', '%FIELD%', '%DATA%', '%DUPLICATE%', '%COMMENT%'],
[
!empty($options['replace']) ? 'REPLACE' : 'INSERT',
$this->parseExtra($query, $options['extra']),
$this->parseTable($query, $options['table']),
$this->parsePartition($query, $options['partition']),
implode(' , ', $fields),
implode(' , ', $values),
$this->parseDuplicate($query, $options['duplicate']),
$this->parseComment($query, $options['comment']),
],
$this->insertAllSql
);
$this->insertAllSql);
}
/**
@@ -259,10 +208,9 @@ class Mysql extends Builder
if (empty($data)) {
return '';
}
$set = [];
foreach ($data as $key => $val) {
$set[] = (strpos($key, '->') ? strstr($key, '->', true) : $key) . ' = ' . $val;
$set[] = $key . ' = ' . $val;
}
return str_replace(
@@ -279,8 +227,7 @@ class Mysql extends Builder
$this->parseLock($query, $options['lock']),
$this->parseComment($query, $options['comment']),
],
$this->updateSql
);
$this->updateSql);
}
/**
@@ -307,8 +254,7 @@ class Mysql extends Builder
$this->parseLock($query, $options['lock']),
$this->parseComment($query, $options['comment']),
],
$this->deleteSql
);
$this->deleteSql);
}
/**

View File

@@ -49,21 +49,12 @@ trait AggregateQuery
}
$options = $this->getOptions();
if (isset($options['cache'])) {
$cache = $options['cache'];
unset($options['cache']);
}
$subSql = $this->options($options)
$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_']);
$query = $this->newQuery()->table([$subSql => '_group_count_']);
$count = $query->aggregate('COUNT', '*');
} else {

View File

@@ -13,6 +13,7 @@ declare (strict_types = 1);
namespace think\db\concern;
use think\db\Raw;
use think\helper\Str;
/**
* JOIN和VIEW查询

View File

@@ -559,4 +559,23 @@ trait ModelRelationQuery
$result->refreshOrigin();
}
/**
* 查询软删除数据
* @access public
* @return Query
*/
public function withTrashed()
{
return $this->model ? $this->model->queryWithTrashed() : $this;
}
/**
* 只查询软删除数据
* @access public
* @return Query
*/
public function onlyTrashed()
{
return $this->model ? $this->model->queryOnlyTrashed() : $this;
}
}

View File

@@ -64,33 +64,6 @@ trait ParamsBind
return isset($this->bind[$key]);
}
/**
* 设置自动参数绑定
* @access public
* @param bool $bind 是否自动参数绑定
* @return $this
*/
public function autoBind(bool $bind)
{
$this->options['auto_bind'] = $bind;
return $this;
}
/**
* 检测是否开启自动参数绑定
* @access public
* @return bool
*/
public function isAutoBind(): bool
{
$autoBind = $this->getConfig('auto_param_bind');
if (null !== $this->getOptions('auto_bind')) {
$autoBind = $this->getOptions('auto_bind');
}
return (bool) $autoBind;
}
/**
* 参数绑定
* @access public

View File

@@ -455,15 +455,18 @@ trait WhereQuery
*/
protected function parseArrayWhereItems(array $field, string $logic)
{
$where = [];
foreach ($field as $key => $val) {
if (is_int($key)) {
$where[] = $val;
} elseif ($val instanceof Raw) {
$where[] = [$key, 'exp', $val];
} else {
$where[] = is_null($val) ? [$key, 'NULL', ''] : [$key, is_array($val) ? 'IN' : '=', $val];
if (key($field) !== 0) {
$where = [];
foreach ($field as $key => $val) {
if ($val instanceof Raw) {
$where[] = [$key, 'exp', $val];
} else {
$where[] = is_null($val) ? [$key, 'NULL', ''] : [$key, is_array($val) ? 'IN' : '=', $val];
}
}
} else {
// 数组批量查询
$where = $field;
}
if (!empty($where)) {

View File

@@ -258,7 +258,7 @@ class Mongo extends Connection
$this->queryStartTime = microtime(true);
if ($session = $this->getSession()) {
$this->cursor = $this->mongo->executeQuery($namespace, $mongoQuery, [
$this->cursor = $this->mongo->executeQuery($namespace, $query, [
'readPreference' => is_null($readPreference) ? new ReadPreference(ReadPreference::RP_PRIMARY) : $readPreference,
'session' => $session,
]);

View File

@@ -60,7 +60,7 @@ class Sqlsrv extends PDOConnection
public function getFields(string $tableName): array
{
[$tableName] = explode(' ', $tableName);
strpos($tableName, '.') && $tableName = substr($tableName, strpos($tableName, '.') + 1);
strpos($tableName,'.') && $tableName = substr($tableName,strpos($tableName,'.') + 1);
$sql = "SELECT column_name, data_type, column_default, is_nullable
FROM information_schema.tables AS t
JOIN information_schema.columns AS c

View File

@@ -67,6 +67,12 @@ abstract class Relation
*/
protected $selfRelation = false;
/**
* 关联数据数量限制
* @var int
*/
protected $withLimit;
/**
* 关联数据字段限制
* @var array
@@ -194,6 +200,18 @@ abstract class Relation
}
}
/**
* 限制关联数据的数量
* @access public
* @param int $limit 关联数量限制
* @return $this
*/
public function withLimit(int $limit)
{
$this->withLimit = $limit;
return $this;
}
/**
* 限制关联数据的字段
* @access public
@@ -226,18 +244,6 @@ abstract class Relation
return $this;
}
/**
* 限制关联数据的数量
* @access public
* @param int $limit 关联数量限制
* @return $this
*/
public function withLimit(int $limit)
{
$this->query->limit($limit);
return $this;
}
/**
* 设置关联数据不存在的时候默认值
* @access public
@@ -275,15 +281,14 @@ abstract class Relation
* @access protected
* @return mixed
*/
protected function getClosureType(Closure $closure, $query = null)
protected function getClosureType(Closure $closure)
{
$reflect = new ReflectionFunction($closure);
$params = $reflect->getParameters();
if (!empty($params)) {
$type = $params[0]->getType();
$query = $query ?: $this->query;
return is_null($type) || Relation::class == $type->getName() ? $this : $query;
$type = $params[0]->getType();
return is_null($type) || Relation::class == $type->getName() ? $this : $this->query;
}
return $this;

View File

@@ -15,6 +15,7 @@ namespace think\model\concern;
use InvalidArgumentException;
use think\db\Raw;
use think\helper\Str;
use think\Model;
use think\model\Relation;
/**
@@ -382,9 +383,7 @@ trait Attribute
} elseif (isset($this->type[$name])) {
// 类型转换
$value = $this->writeTransform($value, $this->type[$name]);
} elseif ($this->isRelationAttr($name)) {
$this->relation[$name] = $value;
} elseif ((array_key_exists($name, $this->origin) || empty($this->origin)) && is_object($value) && method_exists($value, '__toString')) {
} elseif (array_key_exists($name, $this->origin) && is_object($value) && method_exists($value, '__toString')) {
// 对象类型
$value = $value->__toString();
}
@@ -447,7 +446,6 @@ trait Attribute
break;
case 'array':
$value = (array) $value;
// no break
case 'json':
$option = !empty($param) ? (int) $param : JSON_UNESCAPED_UNICODE;
$value = json_encode($value, $option);

View File

@@ -204,55 +204,52 @@ trait Conversion
*/
public function toArray(): array
{
$item = $visible = $hidden = [];
$item = [];
$hasVisible = false;
foreach ($this->visible as $key => $val) {
if (is_string($val)) {
if (strpos($val, '.')) {
[$relation, $name] = explode('.', $val);
$visible[$relation][] = $name;
[$relation, $name] = explode('.', $val);
$this->visible[$relation][] = $name;
} else {
$visible[$val] = true;
$hasVisible = true;
$this->visible[$val] = true;
$hasVisible = true;
}
unset($this->visible[$key]);
}
}
foreach ($this->hidden as $key => $val) {
if (is_string($val)) {
if (strpos($val, '.')) {
[$relation, $name] = explode('.', $val);
$hidden[$relation][] = $name;
[$relation, $name] = explode('.', $val);
$this->hidden[$relation][] = $name;
} else {
$hidden[$val] = true;
$this->hidden[$val] = true;
}
unset($this->hidden[$key]);
}
}
// 追加属性(必须定义获取器)
foreach ($this->append as $key => $name) {
$this->appendAttrToArray($item, $key, $name, $visible, $hidden);
}
// 合并关联数据
$data = array_merge($this->data, $this->relation);
foreach ($data as $key => $val) {
if ($val instanceof Model || $val instanceof ModelCollection) {
// 关联模型对象
if (isset($visible[$key]) && is_array($visible[$key])) {
$val->visible($visible[$key]);
} elseif (isset($hidden[$key]) && is_array($hidden[$key])) {
$val->hidden($hidden[$key], true);
if (isset($this->visible[$key]) && is_array($this->visible[$key])) {
$val->visible($this->visible[$key]);
} elseif (isset($this->hidden[$key]) && is_array($this->hidden[$key])) {
$val->hidden($this->hidden[$key]);
}
// 关联模型对象
if (!isset($hidden[$key]) || true !== $hidden[$key]) {
if (!isset($this->hidden[$key]) || true !== $this->hidden[$key]) {
$item[$key] = $val->toArray();
}
} elseif (isset($visible[$key])) {
} elseif (isset($this->visible[$key])) {
$item[$key] = $this->getAttr($key);
} elseif (!isset($hidden[$key]) && !$hasVisible) {
} elseif (!isset($this->hidden[$key]) && !$hasVisible) {
$item[$key] = $this->getAttr($key);
}
@@ -264,6 +261,11 @@ trait Conversion
}
}
// 追加属性(必须定义获取器)
foreach ($this->append as $key => $name) {
$this->appendAttrToArray($item, $key, $name);
}
if ($this->convertNameToCamel) {
foreach ($item as $key => $val) {
$name = Str::camel($key);
@@ -277,38 +279,27 @@ trait Conversion
return $item;
}
protected function appendAttrToArray(array &$item, $key, $name, array $visible, array $hidden)
protected function appendAttrToArray(array &$item, $key, $name)
{
if (is_array($name)) {
// 批量追加关联对象属性
$relation = $this->getRelationWith($key, $hidden, $visible);
$item[$key] = $relation ? $relation->append($name)->toArray() : [];
// 追加关联对象属性
$relation = $this->getRelation($key, true);
$item[$key] = $relation ? $relation->append($name)
->toArray() : [];
} elseif (strpos($name, '.')) {
// 追加单个关联对象属性
[$key, $attr] = explode('.', $name);
$relation = $this->getRelationWith($key, $hidden, $visible);
$item[$key] = $relation ? $relation->append([$attr])->toArray() : [];
[$key, $attr] = explode('.', $name);
// 追加关联对象属性
$relation = $this->getRelation($key, true);
$item[$key] = $relation ? $relation->append([$attr])
->toArray() : [];
} else {
$value = $this->getAttr($name);
$item[$name] = $value;
$value = $this->getAttr($name);
$item[$name] = $value;
$this->getBindAttrValue($name, $value, $item);
}
}
protected function getRelationWith(string $key, array $hidden, array $visible)
{
$relation = $this->getRelation($key, true);
if ($relation) {
if (isset($visible[$key])) {
$relation->visible($visible[$key]);
} elseif (isset($hidden[$key])) {
$relation->hidden($hidden[$key]);
}
}
return $relation;
}
protected function getBindAttrValue(string $name, $value, array &$item = [])
{
$relation = $this->isRelationAttr($name);

View File

@@ -346,7 +346,7 @@ trait RelationShip
*/
public function bindAttr(string $relation, array $attrs = [])
{
$relation = $this->getRelation($relation, true);
$relation = $this->getRelation($relation);
foreach ($attrs as $key => $attr) {
$key = is_numeric($key) ? $attr : $key;
@@ -735,9 +735,7 @@ trait RelationShip
protected function getRelationData(Relation $modelRelation)
{
if ($this->parent && !$modelRelation->isSelfRelation()
&& get_class($this->parent) == get_class($modelRelation->getModel())
&& $modelRelation instanceof OneToOne
) {
&& get_class($this->parent) == get_class($modelRelation->getModel())) {
return $this->parent;
}

View File

@@ -18,18 +18,14 @@ use think\Model;
/**
* 数据软删除
* @mixin Model
* @method $this withTrashed()
* @method $this onlyTrashed()
*/
trait SoftDelete
{
public function db($scope = []): Query
{
$query = parent::db($scope);
$this->withNoTrashed($query);
return $query;
}
/**
* 是否包含软删除数据
* @var bool
*/
protected $withTrashed = false;
/**
* 判断当前实例是否被软删除
@@ -47,18 +43,74 @@ trait SoftDelete
return false;
}
public function scopeWithTrashed(Query $query)
/**
* 查询软删除数据
* @access public
* @return Query
*/
public static function withTrashed(): Query
{
$query->removeOption('soft_delete');
$model = new static();
return $model->withTrashedData(true)->db();
}
public function scopeOnlyTrashed(Query $query)
/**
* 查询软删除数据
* @access public
* @return Query
*/
public function queryWithTrashed(): Query
{
return $this->withTrashedData(true)->db();
}
/**
* 是否包含软删除数据
* @access protected
* @param bool $withTrashed 是否包含软删除数据
* @return $this
*/
protected function withTrashedData(bool $withTrashed)
{
$this->withTrashed = $withTrashed;
return $this;
}
/**
* 只查询软删除数据
* @access public
* @return Query
*/
public static function onlyTrashed(): Query
{
$model = new static();
$field = $model->getDeleteTimeField(true);
if ($field) {
return $model
->db()
->useSoftDelete($field, $model->getWithTrashedExp());
}
return $model->db();
}
/**
* 只查询软删除数据
* @access public
* @return Query
*/
public function queryOnlyTrashed(): Query
{
$field = $this->getDeleteTimeField(true);
if ($field) {
$query->useSoftDelete($field, $this->getWithTrashedExp());
return $this->db()
->useSoftDelete($field, $this->getWithTrashedExp());
}
return $this->db();
}
/**
@@ -87,9 +139,9 @@ trait SoftDelete
if ($name && !$force) {
// 软删除
$this->set($name, $this->autoWriteTimestamp());
$this->set($name, $this->autoWriteTimestamp($name));
$this->exists()->withEvent(false)->save();
$result = $this->exists()->withEvent(false)->save();
$this->withEvent(true);
} else {
@@ -97,7 +149,7 @@ trait SoftDelete
$where = $this->getWhere();
// 删除当前模型数据
$this->db()
$result = $this->db()
->where($where)
->removeOption('soft_delete')
->delete();
@@ -120,8 +172,8 @@ trait SoftDelete
/**
* 删除记录
* @access public
* @param mixed $data 主键列表 支持闭包查询条件
* @param bool $force 是否强制删除
* @param mixed $data 主键列表 支持闭包查询条件
* @param bool $force 是否强制删除
* @return bool
*/
public static function destroy($data, bool $force = false): bool
@@ -130,20 +182,18 @@ trait SoftDelete
if (empty($data) && 0 !== $data) {
return false;
}
$model = (new static());
$query = $model->db(false);
// 仅当强制删除时包含软删除数据
$model = (new static());
if ($force) {
$query->removeOption('soft_delete');
$model->withTrashedData(true);
}
$query = $model->db(false);
if (is_array($data) && key($data) !== 0) {
$query->where($data);
$data = null;
} elseif ($data instanceof \Closure) {
call_user_func_array($data, [&$query]);
call_user_func_array($data, [ & $query]);
$data = null;
} elseif (is_null($data)) {
return false;
@@ -152,7 +202,6 @@ trait SoftDelete
$resultSet = $query->select($data);
foreach ($resultSet as $result) {
/** @var Model $result */
$result->force($force)->delete();
}
@@ -162,7 +211,7 @@ trait SoftDelete
/**
* 恢复被软删除的记录
* @access public
* @param array $where 更新条件
* @param array $where 更新条件
* @return bool
*/
public function restore($where = []): bool
@@ -194,7 +243,7 @@ trait SoftDelete
/**
* 获取软删除字段
* @access protected
* @param bool $read 是否查询操作 写操作的时候会自动去掉表别名
* @param bool $read 是否查询操作 写操作的时候会自动去掉表别名
* @return string|false
*/
protected function getDeleteTimeField(bool $read = false)
@@ -220,7 +269,7 @@ trait SoftDelete
/**
* 查询的时候默认排除软删除数据
* @access protected
* @param Query $query
* @param Query $query
* @return void
*/
protected function withNoTrashed(Query $query): void

View File

@@ -179,7 +179,7 @@ trait TimeStamp
protected function formatDateTime($format, $time = 'now', bool $timestamp = false)
{
if (empty($time)) {
return $time;
return;
}
if (false === $format) {

View File

@@ -14,6 +14,7 @@ namespace think\model\relation;
use Closure;
use think\db\BaseQuery as Query;
use think\helper\Str;
use think\Model;
/**
@@ -240,7 +241,7 @@ class BelongsTo extends OneToOne
if (!empty($this->bindAttr)) {
// 绑定关联属性
$this->bindAttr($result, $relationModel);
$result->hidden([$relation], true);
$result->hidden([$relation]);
}
}
}
@@ -282,7 +283,7 @@ class BelongsTo extends OneToOne
if (!empty($this->bindAttr)) {
// 绑定关联属性
$this->bindAttr($result, $relationModel);
$result->hidden([$relation], true);
$result->hidden([$relation]);
}
}

View File

@@ -346,11 +346,6 @@ class BelongsToMany extends Relation
$closure($this->getClosureType($closure));
}
$withLimit = $this->query->getOptions('limit');
if ($withLimit) {
$this->query->removeOption('limit');
}
// 预载入关联查询 支持嵌套预载入
$list = $this->belongsToManyQuery($this->foreignKey, $this->localKey, $where)
->with($subRelation)
@@ -358,12 +353,12 @@ class BelongsToMany extends Relation
->select();
// 组装模型数据
$data = [];
$data = [];
foreach ($list as $set) {
$pivot = $this->matchPivot($set);
$key = $pivot[$this->localKey];
if ($withLimit && isset($data[$key]) && count($data[$key]) >= $withLimit) {
if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) {
continue;
}
@@ -394,6 +389,10 @@ class BelongsToMany extends Relation
$fields = $this->getQueryFields($tableName);
if ($this->withLimit) {
$this->query->limit($this->withLimit);
}
$this->query
->field($fields)
->tableField(true, $table, 'pivot', 'pivot__')

View File

@@ -15,6 +15,7 @@ namespace think\model\relation;
use Closure;
use think\Collection;
use think\db\BaseQuery as Query;
use think\helper\Str;
use think\Model;
use think\model\Relation;
@@ -57,6 +58,10 @@ class HasMany extends Relation
$closure($this->getClosureType($closure));
}
if ($this->withLimit) {
$this->query->limit($this->withLimit);
}
return $this->query
->where($this->foreignKey, $this->parent->{$this->localKey})
->relation($subRelation)
@@ -205,11 +210,6 @@ class HasMany extends Relation
$this->query->withoutField($this->withoutField);
}
$withLimit = $this->query->getOptions('limit');
if ($withLimit) {
$this->query->removeOption('limit');
}
$list = $this->query
->where($where)
->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null)
@@ -217,12 +217,12 @@ class HasMany extends Relation
->select();
// 组装模型数据
$data = [];
$data = [];
foreach ($list as $set) {
$key = $set->$foreignKey;
if ($withLimit && isset($data[$key]) && count($data[$key]) >= $withLimit) {
if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) {
continue;
}
@@ -241,10 +241,6 @@ class HasMany extends Relation
*/
public function save($data, bool $replace = true)
{
if ($data instanceof Model) {
$data = $data->getData();
}
$model = $this->make();
return $model->replace($replace)->save($data) ? $model : false;
@@ -264,7 +260,7 @@ class HasMany extends Relation
// 保存关联表数据
$data[$this->foreignKey] = $this->parent->{$this->localKey};
return (new $this->model($data))->setSuffix($this->getModel()->getSuffix());
return new $this->model($data);
}
/**

View File

@@ -79,6 +79,10 @@ class HasManyThrough extends Relation
$this->baseQuery();
if ($this->withLimit) {
$this->query->limit($this->withLimit);
}
return $this->query->relation($subRelation)
->select()
->setParent(clone $this->parent);
@@ -260,24 +264,19 @@ class HasManyThrough extends Relation
$throughKey = Str::snake(class_basename($this->model)) . "." . $this->throughKey;
}
$withLimit = $this->query->getOptions('limit');
if ($withLimit) {
$this->query->removeOption('limit');
}
$list = $this->query
->where($throughKey, 'in', $keys)
->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null)
->select();
// 组装模型数据
$data = [];
$keys = $throughList->column($this->foreignKey, $this->throughPk);
$data = [];
$keys = $throughList->column($this->foreignKey, $this->throughPk);
foreach ($list as $set) {
$key = $keys[$set->{$this->throughKey}];
if ($withLimit && isset($data[$key]) && count($data[$key]) >= $withLimit) {
if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) {
continue;
}

View File

@@ -14,6 +14,7 @@ namespace think\model\relation;
use Closure;
use think\db\BaseQuery as Query;
use think\helper\Str;
use think\Model;
/**
@@ -239,7 +240,7 @@ class HasOne extends OneToOne
if (!empty($this->bindAttr)) {
// 绑定关联属性
$this->bindAttr($result, $relationModel);
$result->hidden([$relation], true);
$result->hidden([$relation]);
}
}
}
@@ -281,7 +282,7 @@ class HasOne extends OneToOne
if (!empty($this->bindAttr)) {
// 绑定关联属性
$this->bindAttr($result, $relationModel);
$result->hidden([$relation], true);
$result->hidden([$relation]);
}
}

View File

@@ -12,6 +12,7 @@
namespace think\model\relation;
use Closure;
use think\helper\Str;
use think\Model;
/**
@@ -151,10 +152,14 @@ class HasOneThrough extends HasManyThrough
->select();
// 组装模型数据
return array_map(function ($key) use ($list) {
$set = $list->where($this->throughKey, '=', $key)->first();
return $set ? clone $set : null;
}, $keys);
$data = [];
$keys = array_flip($keys);
foreach ($list as $set) {
$data[$keys[$set->{$this->throughKey}]] = $set;
}
return $data;
}
}

View File

@@ -15,6 +15,7 @@ use Closure;
use think\Collection;
use think\db\BaseQuery as Query;
use think\db\exception\DbException as Exception;
use think\helper\Str;
use think\Model;
use think\model\Relation;
@@ -76,6 +77,10 @@ class MorphMany extends Relation
$this->baseQuery();
if ($this->withLimit) {
$this->query->limit($this->withLimit);
}
return $this->query->relation($subRelation)
->select()
->setParent(clone $this->parent);
@@ -253,11 +258,6 @@ class MorphMany extends Relation
$closure($this->getClosureType($closure));
}
$withLimit = $this->query->getOptions('limit');
if ($withLimit) {
$this->query->removeOption('limit');
}
$list = $this->query
->where($where)
->with($subRelation)
@@ -266,11 +266,11 @@ class MorphMany extends Relation
$morphKey = $this->morphKey;
// 组装模型数据
$data = [];
$data = [];
foreach ($list as $set) {
$key = $set->$morphKey;
if ($withLimit && isset($data[$key]) && count($data[$key]) >= $withLimit) {
if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) {
continue;
}
@@ -289,10 +289,6 @@ class MorphMany extends Relation
*/
public function save($data, bool $replace = true)
{
if ($data instanceof Model) {
$data = $data->getData();
}
$model = $this->make();
return $model->replace($replace)->save($data) ? $model : false;
@@ -315,7 +311,7 @@ class MorphMany extends Relation
$data[$this->morphKey] = $this->parent->$pk;
$data[$this->morphType] = $this->type;
return (new $this->model($data))->setSuffix($this->getModel()->getSuffix());
return new $this->model($data);
}
/**

View File

@@ -14,6 +14,7 @@ namespace think\model\relation;
use Closure;
use think\db\BaseQuery as Query;
use think\db\exception\DbException as Exception;
use think\helper\Str;
use think\Model;
use think\model\Relation;
@@ -259,10 +260,6 @@ class MorphOne extends Relation
*/
public function save($data, bool $replace = true)
{
if ($data instanceof Model) {
$data = $data->getData();
}
$model = $this->make();
return $model->replace($replace)->save($data) ? $model : false;
}
@@ -284,7 +281,7 @@ class MorphOne extends Relation
$data[$this->morphKey] = $this->parent->$pk;
$data[$this->morphType] = $this->type;
return (new $this->model($data))->setSuffix($this->getModel()->getSuffix());
return new $this->model($data);
}
/**

View File

@@ -13,7 +13,6 @@ namespace think\model\relation;
use Closure;
use think\db\exception\DbException as Exception;
use think\db\Query;
use think\helper\Str;
use think\Model;
use think\model\Relation;
@@ -47,16 +46,14 @@ class MorphTo extends Relation
*/
protected $relation;
protected $queryCaller = [];
/**
* 架构函数
* @access public
* @param Model $parent 上级模型对象
* @param string $morphType 多态字段名
* @param string $morphKey 外键名
* @param array $alias 多态别名定义
* @param ?string $relation 关联名
* @param Model $parent 上级模型对象
* @param string $morphType 多态字段名
* @param string $morphKey 外键名
* @param array $alias 多态别名定义
* @param string $relation 关联名
*/
public function __construct(Model $parent, string $morphType, string $morphKey, array $alias = [], string $relation = null)
{
@@ -83,8 +80,8 @@ class MorphTo extends Relation
/**
* 延迟获取关联数据
* @access public
* @param array $subRelation 子关联名
* @param ?Closure $closure 闭包查询条件
* @param array $subRelation 子关联名
* @param Closure $closure 闭包查询条件
* @return Model
*/
public function getRelation(array $subRelation = [], Closure $closure = null)
@@ -98,7 +95,7 @@ class MorphTo extends Relation
// 主键数据
$pk = $this->parent->$morphKey;
$relationModel = $this->buildQuery((new $model)->relation($subRelation))->find($pk);
$relationModel = (new $model)->relation($subRelation)->find($pk);
if ($relationModel) {
$relationModel->setParent(clone $this->parent);
@@ -110,11 +107,11 @@ class MorphTo extends Relation
/**
* 根据关联条件查询当前模型
* @access public
* @param string $operator 比较操作符
* @param integer $count 个数
* @param string $id 关联表的统计字段
* @param string $joinType JOIN类型
* @param Query $query Query对象
* @param string $operator 比较操作符
* @param integer $count 个数
* @param string $id 关联表的统计字段
* @param string $joinType JOIN类型
* @param Query $query Query对象
* @return Query
*/
public function has(string $operator = '>=', int $count = 1, string $id = '*', string $joinType = '', Query $query = null)
@@ -125,46 +122,22 @@ class MorphTo extends Relation
/**
* 根据关联条件查询当前模型
* @access public
* @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @param string $joinType JOIN类型
* @param ?Query $query Query对象
* @param mixed $where 查询条件(数组或者闭包)
* @param mixed $fields 字段
* @param string $joinType JOIN类型
* @param Query $query Query对象
* @return Query
*/
public function hasWhere($where = [], $fields = null, string $joinType = '', Query $query = null)
{
$alias = class_basename($this->parent);
$types = $this->parent->distinct()->column($this->morphType);
$query = $query ?: $this->parent->db();
return $query->alias($alias)
->where(function (Query $query) use ($types, $where, $alias) {
foreach ($types as $type) {
if ($type) {
$query->whereExists(function (Query $query) use ($type, $where, $alias) {
$class = $this->parseModel($type);
/** @var Model $model */
$model = new $class();
$table = $model->getTable();
$query
->table($table)
->where($alias . '.' . $this->morphType, $type)
->whereRaw("`{$alias}`.`{$this->morphKey}`=`{$table}`.`{$model->getPk()}`")
->where($where);
}, 'OR');
}
}
});
throw new Exception('relation not support: hasWhere');
}
/**
* 解析模型的完整命名空间
* @access protected
* @param string $model 模型名(或者完整类名)
* @return Model
* @param string $model 模型名(或者完整类名)
* @return string
*/
protected function parseModel(string $model): string
{
@@ -185,7 +158,7 @@ class MorphTo extends Relation
/**
* 设置多态别名
* @access public
* @param array $alias 别名定义
* @param array $alias 别名定义
* @return $this
*/
public function setAlias(array $alias)
@@ -200,7 +173,7 @@ class MorphTo extends Relation
* @access public
* @return $this
*/
public function removeOption(string $option = '')
public function removeOption()
{
return $this;
}
@@ -208,11 +181,11 @@ class MorphTo extends Relation
/**
* 预载入关联查询
* @access public
* @param array $resultSet 数据集
* @param string $relation 当前关联名
* @param array $subRelation 子关联名
* @param ?Closure $closure 闭包
* @param array $cache 关联缓存
* @param array $resultSet 数据集
* @param string $relation 当前关联名
* @param array $subRelation 子关联名
* @param Closure $closure 闭包
* @param array $cache 关联缓存
* @return void
* @throws Exception
*/
@@ -238,8 +211,8 @@ class MorphTo extends Relation
if (!\is_null($closure)) {
$obj = $closure($obj);
}
$pk = $obj->getPk();
$list = $obj->with($subRelation)
$pk = $obj->getPk();
$list = $obj->with($subRelation)
->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null)
->select($val);
$data = [];
@@ -269,11 +242,11 @@ class MorphTo extends Relation
/**
* 预载入关联查询
* @access public
* @param Model $result 数据对象
* @param string $relation 当前关联名
* @param array $subRelation 子关联名
* @param ?Closure $closure 闭包
* @param array $cache 关联缓存
* @param Model $result 数据对象
* @param string $relation 当前关联名
* @param array $subRelation 子关联名
* @param Closure $closure 闭包
* @param array $cache 关联缓存
* @return void
*/
public function eagerlyResult(Model $result, string $relation, array $subRelation = [], Closure $closure = null, array $cache = []): void
@@ -287,42 +260,36 @@ class MorphTo extends Relation
/**
* 关联统计
* @access public
* @param Model $result 数据对象
* @param ?Closure $closure 闭包
* @param string $aggregate 聚合查询方法
* @param string $field 字段
* @param Model $result 数据对象
* @param Closure $closure 闭包
* @param string $aggregate 聚合查询方法
* @param string $field 字段
* @return integer
*/
public function relationCount(Model $result, Closure $closure = null, string $aggregate = 'count', string $field = '*')
{
}
{}
/**
* 多态MorphTo 关联模型预查询
* @access protected
* @param string $model 关联模型对象
* @param string $relation 关联名
* @param Model $result
* @param array $subRelation 子关联
* @param array $cache 关联缓存
* @param string $model 关联模型对象
* @param string $relation 关联名
* @param Model $result
* @param array $subRelation 子关联
* @param array $cache 关联缓存
* @return void
*/
protected function eagerlyMorphToOne(string $model, string $relation, Model $result, array $subRelation = [], array $cache = []): void
{
// 预载入关联查询 支持嵌套预载入
$pk = $this->parent->{$this->morphKey};
$pk = $this->parent->{$this->morphKey};
$data = (new $model)->with($subRelation)
->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null)
->find($pk);
$data = null;
if (\class_exists($model)) {
$data = (new $model)->with($subRelation)
->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null)
->find($pk);
if ($data) {
$data->setParent(clone $result);
$data->exists(true);
}
if ($data) {
$data->setParent(clone $result);
$data->exists(true);
}
$result->setRelation($relation, $data ?: null);
@@ -331,8 +298,8 @@ class MorphTo extends Relation
/**
* 添加关联数据
* @access public
* @param Model $model 关联模型对象
* @param string $type 多态类型
* @param Model $model 关联模型对象
* @param string $type 多态类型
* @return Model
*/
public function associate(Model $model, string $type = ''): Model
@@ -365,18 +332,4 @@ class MorphTo extends Relation
return $this->parent->setRelation($this->relation, null);
}
protected function buildQuery(Query $query)
{
foreach ($this->queryCaller as $caller) {
call_user_func_array([$query, $caller[0]], $caller[1]);
}
return $query;
}
public function __call($method, $args)
{
$this->queryCaller[] = [$method, $args];
return $this;
}
}

View File

@@ -216,7 +216,12 @@ class MorphToMany extends BelongsToMany
}
$fields = $this->getQueryFields($tableName);
$query = $this->query
if ($this->withLimit) {
$this->query->limit($this->withLimit);
}
$query = $this->query
->field($fields)
->tableField(true, $table, 'pivot', 'pivot__');
@@ -244,11 +249,6 @@ class MorphToMany extends BelongsToMany
$closure($this->getClosureType($closure));
}
$withLimit = $this->query->getOptions('limit');
if ($withLimit) {
$this->query->removeOption('limit');
}
// 预载入关联查询 支持嵌套预载入
$list = $this->belongsToManyQuery($this->foreignKey, $this->localKey, $where)
->with($subRelation)
@@ -256,7 +256,7 @@ class MorphToMany extends BelongsToMany
->select();
// 组装模型数据
$data = [];
$data = [];
foreach ($list as $set) {
$pivot = [];
foreach ($set->getData() as $key => $val) {
@@ -271,7 +271,7 @@ class MorphToMany extends BelongsToMany
$key = $pivot[$this->localKey];
if ($withLimit && isset($data[$key]) && count($data[$key]) >= $withLimit) {
if ($this->withLimit && isset($data[$key]) && count($data[$key]) >= $this->withLimit) {
continue;
}
@@ -300,10 +300,10 @@ class MorphToMany extends BelongsToMany
$model = new $this->model;
$id = $model->insertGetId($data);
}
} elseif (is_numeric($data) || is_string($data)) {
} else if (is_numeric($data) || is_string($data)) {
// 根据关联表主键直接写入中间表
$id = $data;
} elseif ($data instanceof Model) {
} else if ($data instanceof Model) {
// 根据关联表主键直接写入中间表
$id = $data->getKey();
}
@@ -371,10 +371,10 @@ class MorphToMany extends BelongsToMany
{
if (is_array($data)) {
$id = $data;
} elseif (is_numeric($data) || is_string($data)) {
} else if (is_numeric($data) || is_string($data)) {
// 根据关联表主键直接写入中间表
$id = $data;
} elseif ($data instanceof Model) {
} else if ($data instanceof Model) {
// 根据关联表主键直接写入中间表
$id = $data->getKey();
}
@@ -441,7 +441,7 @@ class MorphToMany extends BelongsToMany
if (!in_array($id, $current)) {
$this->attach($id, $attributes);
$changes['attached'][] = $id;
} elseif (count($attributes) > 0 && $this->attach($id, $attributes)) {
} else if (count($attributes) > 0 && $this->attach($id, $attributes)) {
$changes['updated'][] = $id;
}
}
@@ -481,7 +481,7 @@ class MorphToMany extends BelongsToMany
{
if (is_array($map)) {
static::$morphMap = $merge && static::$morphMap
? $map + static::$morphMap : $map;
? $map + static::$morphMap : $map;
}
return static::$morphMap;

View File

@@ -91,28 +91,14 @@ abstract class OneToOne extends Relation
$query->via($joinAlias);
if ($this instanceof BelongsTo) {
$foreignKeyExp = $this->foreignKey;
if (strpos($foreignKeyExp, '.') === false) {
$foreignKeyExp = $name . '.' . $this->foreignKey;
}
$joinOn = $foreignKeyExp . '=' . $joinAlias . '.' . $this->localKey;
$joinOn = $name . '.' . $this->foreignKey . '=' . $joinAlias . '.' . $this->localKey;
} else {
$foreignKeyExp = $this->foreignKey;
if (strpos($foreignKeyExp, '.') === false) {
$foreignKeyExp = $joinAlias . '.' . $this->foreignKey;
}
$joinOn = $name . '.' . $this->localKey . '=' . $foreignKeyExp;
$joinOn = $name . '.' . $this->localKey . '=' . $joinAlias . '.' . $this->foreignKey;
}
if ($closure) {
// 执行闭包查询
$closure($this->getClosureType($closure, $query));
$closure($this->getClosureType($closure));
// 使用withField指定获取关联的字段
if ($this->withField) {
@@ -201,10 +187,6 @@ abstract class OneToOne extends Relation
*/
public function save($data, bool $replace = true)
{
if ($data instanceof Model) {
$data = $data->getData();
}
$model = $this->make();
return $model->replace($replace)->save($data) ? $model : false;
@@ -224,9 +206,10 @@ abstract class OneToOne extends Relation
// 保存关联表数据
$data[$this->foreignKey] = $this->parent->{$this->localKey};
return (new $this->model($data))->setSuffix($this->getModel()->getSuffix());
return new $this->model($data);
}
/**
* 绑定关联表的属性到父模型属性
* @access public

View File

@@ -21,11 +21,12 @@
"think\\test\\queue\\": "tests"
}
},
"minimum-stability": "dev",
"require": {
"ext-json": "*",
"topthink/framework": "^6.0 || ^8.0",
"symfony/process": ">=4.2",
"nesbot/carbon": ">=2.16"
"topthink/framework": "^6.0",
"symfony/process": "^4.2",
"nesbot/carbon": "^2.16"
},
"extra": {
"think": {
@@ -33,13 +34,13 @@
"think\\queue\\Service"
],
"config": {
"queue": "src/config/queue.php"
"queue": "src/config.php"
}
}
},
"require-dev": {
"phpunit/phpunit": "^6.2",
"mockery/mockery": "^1.2",
"topthink/think-migration": "^3.0"
"topthink/think-migration": "^3.0.0"
}
}

View File

@@ -0,0 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
return [
'default' => 'sync',
'connections' => [
'sync' => [
'type' => 'sync',
],
'database' => [
'type' => 'database',
'queue' => 'default',
'table' => 'jobs',
'connection' => null,
],
'redis' => [
'type' => 'redis',
'queue' => 'default',
'host' => '127.0.0.1',
'port' => 6379,
'password' => '',
'select' => 0,
'timeout' => 0,
'persistent' => false,
],
],
'failed' => [
'type' => 'none',
'table' => 'failed_jobs',
],
];

View File

@@ -13,6 +13,6 @@ class Queue extends Facade
{
protected static function getFacadeClass()
{
return 'queue';
return \think\Queue::class;
}
}

View File

@@ -26,7 +26,7 @@ class CallQueuedHandler
{
$command = unserialize($data['command']);
$this->app->invoke([$command, 'handle'], [$job]);
$this->app->invoke([$command, 'handle']);
if (!$job->isDeletedOrReleased()) {
$job->delete();

View File

@@ -194,11 +194,23 @@ abstract class Job
*/
protected function resolve($name, $param)
{
$namespace = $this->app->getNamespace() . '\\job\\';
// $namespace = $this->app->getNamespace() . '\\job\\';
////
//// $class = false !== strpos($name, '\\') ? $name : $namespace . Str::studly($name);
////
//// return $this->app->make($class, [$param], true);
if (strpos($name, '\\') === false) {
$class = false !== strpos($name, '\\') ? $name : $namespace . Str::studly($name);
if (strpos($name, '/') === false) {
$app = '';
} else {
list($app, $name) = explode('/', $name, 2);
}
return $this->app->make($class, [$param], true);
$name = ($this->app->config->get('app.app_namespace') ?: 'app\\') . ($app ? strtolower($app) . '\\' : '') . 'job\\' . $name;
}
return $this->app->make($name, [$param], true);
}
public function getResolvedJob()

View File

@@ -52,7 +52,7 @@ class Worker
*/
public $paused = false;
public function __construct(Queue $queue, Event $event, Handle $handle, ?Cache $cache = null)
public function __construct(Queue $queue, Event $event, Handle $handle, Cache $cache = null)
{
$this->queue = $queue;
$this->event = $event;

View File

@@ -245,7 +245,7 @@ class Template
// 页面缓存
ob_start();
if (version_compare(PHP_VERSION, '8.0', '>=')) {
if (PHP_VERSION > 8.0) {
ob_implicit_flush(false);
} else {
ob_implicit_flush(0);
@@ -1074,9 +1074,6 @@ class Template
switch (strtolower($fun)) {
case 'raw':
break;
case 'htmlentities':
$name = 'htmlentities((string) ' . $name . ')';
break;
case 'date':
$name = 'date(' . $args[1] . ',!is_numeric(' . $name . ')? strtotime(' . $name . ') : ' . $name . ')';
break;

View File

@@ -13,8 +13,7 @@ namespace think\facade;
if (class_exists('think\Facade')) {
class Facade extends \think\Facade
{
}
{}
} else {
class Facade
{
@@ -32,8 +31,7 @@ if (class_exists('think\Facade')) {
* @return string
*/
protected static function getFacadeClass()
{
}
{}
/**
* 创建Facade实例
@@ -54,6 +52,7 @@ if (class_exists('think\Facade')) {
}
return self::$instance;
}
// 调用实际类的方法