From 689376a5d9476283a671472ad13acca5b94f90c5 Mon Sep 17 00:00:00 2001 From: molong Date: Mon, 6 Feb 2017 17:22:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=85=E6=A0=B8=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/convention.php | 4 - core/helper.php | 5 +- core/library/think/Model.php | 49 ++++-- core/library/think/Url.php | 3 +- core/library/think/Validate.php | 3 +- core/library/think/db/Builder.php | 5 +- core/library/think/db/Connection.php | 23 ++- core/library/think/db/Query.php | 157 ++++++++++++------ core/library/think/db/connector/Mysql.php | 14 ++ .../think/model/relation/BelongsToMany.php | 15 +- core/library/think/model/relation/HasMany.php | 17 +- core/library/traits/controller/Jump.php | 5 +- core/library/traits/model/SoftDelete.php | 4 +- 13 files changed, 213 insertions(+), 91 deletions(-) diff --git a/core/convention.php b/core/convention.php index 8152066b..b6f23e28 100644 --- a/core/convention.php +++ b/core/convention.php @@ -274,10 +274,6 @@ return [ 'datetime_format' => 'Y-m-d H:i:s', // 是否需要进行SQL性能分析 'sql_explain' => false, - // Builder类 - 'builder' => '', - // Query类 - 'query' => '\\think\\db\\Query', ], //分页配置 diff --git a/core/helper.php b/core/helper.php index 543942be..da0dc9c5 100644 --- a/core/helper.php +++ b/core/helper.php @@ -495,15 +495,16 @@ if (!function_exists('redirect')) { * @param mixed $url 重定向地址 支持Url::build方法的地址 * @param array|integer $params 额外参数 * @param integer $code 状态码 + * @param array $with 隐式传参 * @return \think\response\Redirect */ - function redirect($url = [], $params = [], $code = 302) + function redirect($url = [], $params = [], $code = 302, $with = []) { if (is_integer($params)) { $code = $params; $params = []; } - return Response::create($url, 'redirect', $code)->params($params); + return Response::create($url, 'redirect', $code)->params($params)->with($with); } } diff --git a/core/library/think/Model.php b/core/library/think/Model.php index 085ca053..61baa3a7 100644 --- a/core/library/think/Model.php +++ b/core/library/think/Model.php @@ -189,7 +189,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } // 全局作用域 if ($baseQuery && method_exists($this, 'base')) { - call_user_func_array([$this, 'base'], [& self::$links[$model]]); + call_user_func_array([$this, 'base'], [ & self::$links[$model]]); } // 返回当前模型的数据库查询对象 return self::$links[$model]; @@ -326,10 +326,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess break; } } elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [ - 'datetime', - 'date', - 'timestamp' - ]) + 'datetime', + 'date', + 'timestamp', + ]) ) { $value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $this->dateFormat); } else { @@ -350,7 +350,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess { if (false !== strpos($format, '\\')) { $time = new $format($time); - } elseif (!$timestamp) { + } elseif (!$timestamp && false !== $format) { $time = date($format, $time); } return $time; @@ -439,10 +439,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $value = $this->readTransform($value, $this->type[$name]); } elseif (in_array($name, [$this->createTime, $this->updateTime])) { if (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [ - 'datetime', - 'date', - 'timestamp' - ]) + 'datetime', + 'date', + 'timestamp', + ]) ) { $value = $this->formatDateTime(strtotime($value), $this->dateFormat); } else { @@ -1018,6 +1018,21 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return $this; } + /** + * 设置只读字段 + * @access public + * @param mixed $field 只读字段 + * @return $this + */ + public function readonly($field) + { + if (is_string($field)) { + $field = explode(',', $field); + } + $this->readonly = $field; + return $this; + } + /** * 是否为更新数据 * @access public @@ -1219,7 +1234,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess if (isset(self::$event[$this->class][$event])) { foreach (self::$event[$this->class][$event] as $callback) { if (is_callable($callback)) { - $result = call_user_func_array($callback, [& $params]); + $result = call_user_func_array($callback, [ & $params]); if (false === $result) { return false; } @@ -1275,6 +1290,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ public static function get($data = null, $with = [], $cache = false) { + if (true === $with || is_int($with)) { + $cache = $with; + $with = []; + } $query = static::parseQuery($data, $with, $cache); return $query->find($data); } @@ -1290,6 +1309,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ public static function all($data = null, $with = [], $cache = false) { + if (true === $with || is_int($with)) { + $cache = $with; + $with = []; + } $query = static::parseQuery($data, $with, $cache); return $query->select($data); } @@ -1309,7 +1332,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $result = $result->where($data); $data = null; } elseif ($data instanceof \Closure) { - call_user_func_array($data, [& $result]); + call_user_func_array($data, [ & $result]); $data = null; } elseif ($data instanceof Query) { $result = $data->with($with)->cache($cache); @@ -1332,7 +1355,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $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 0; diff --git a/core/library/think/Url.php b/core/library/think/Url.php index 51c846d7..d7dfd973 100644 --- a/core/library/think/Url.php +++ b/core/library/think/Url.php @@ -153,7 +153,8 @@ class Url // 检测域名 $domain = self::parseDomain($url, $domain); // URL组装 - $url = $domain . (self::$root ?: Request::instance()->root()) . '/' . ltrim($url, '/'); + $url = $domain . rtrim(self::$root ?: Request::instance()->root(), '/') . '/' . ltrim($url, '/'); + self::$bindCheck = false; return $url; } diff --git a/core/library/think/Validate.php b/core/library/think/Validate.php index 9a6f58ab..2f728a60 100644 --- a/core/library/think/Validate.php +++ b/core/library/think/Validate.php @@ -656,7 +656,7 @@ class Validate if (!in_array($rule, ['ipv4', 'ipv6'])) { $rule = 'ipv4'; } - return $this->filter($value, FILTER_VALIDATE_IP, 'ipv6' == $rule ? FILTER_FLAG_IPV6 : FILTER_FLAG_IPV4); + return $this->filter($value, [FILTER_VALIDATE_IP, 'ipv6' == $rule ? FILTER_FLAG_IPV6 : FILTER_FLAG_IPV4]); } /** @@ -872,6 +872,7 @@ class Validate list($rule, $param) = explode(',', $rule); } elseif (is_array($rule)) { $param = isset($rule[1]) ? $rule[1] : null; + $rule = $rule[0]; } else { $param = null; } diff --git a/core/library/think/db/Builder.php b/core/library/think/db/Builder.php index 380fe239..9034076e 100644 --- a/core/library/think/db/Builder.php +++ b/core/library/think/db/Builder.php @@ -250,7 +250,10 @@ abstract class Builder // 使用闭包查询 $query = new Query($this->connection); call_user_func_array($value, [ & $query]); - $str[] = ' ' . $key . ' ( ' . $this->buildWhere($query->getOptions('where'), $options) . ' )'; + $whereClause = $this->buildWhere($query->getOptions('where'), $options); + if (!empty($whereClause)) { + $str[] = ' ' . $key . ' ( ' . $whereClause . ' )'; + } } elseif (strpos($field, '|')) { // 不同字段使用相同查询条件(OR) $array = explode('|', $field); diff --git a/core/library/think/db/Connection.php b/core/library/think/db/Connection.php index b1f730bf..0887093d 100644 --- a/core/library/think/db/Connection.php +++ b/core/library/think/db/Connection.php @@ -108,6 +108,8 @@ abstract class Connection 'builder' => '', // Query类 'query' => '\\think\\db\\Query', + // 是否需要断线重连 + 'break_reconnect' => false, ]; // PDO连接参数 @@ -391,6 +393,9 @@ abstract class Connection // 返回结果集 return $this->getResult($pdo, $procedure); } catch (\PDOException $e) { + if ($this->config['break_reconnect'] && $this->isBreak($e)) { + return $this->close()->query($sql, $bind, $master, $pdo); + } throw new PDOException($e, $this->config, $this->getLastsql()); } } @@ -446,6 +451,9 @@ abstract class Connection $this->numRows = $this->PDOStatement->rowCount(); return $this->numRows; } catch (\PDOException $e) { + if ($this->config['break_reconnect'] && $this->isBreak($e)) { + return $this->close()->execute($sql, $bind); + } throw new PDOException($e, $this->config, $this->getLastsql()); } } @@ -747,8 +755,9 @@ abstract class Connection } /** - * 关闭数据库 + * 关闭数据库(或者重新连接) * @access public + * @return $this */ public function close() { @@ -756,6 +765,18 @@ abstract class Connection $this->linkWrite = null; $this->linkRead = null; $this->links = []; + return $this; + } + + /** + * 是否断线 + * @access protected + * @param \PDOException $e 异常 + * @return bool + */ + protected function isBreak($e) + { + return false; } /** diff --git a/core/library/think/db/Query.php b/core/library/think/db/Query.php index 26a52c85..3d080dcc 100644 --- a/core/library/think/db/Query.php +++ b/core/library/think/db/Query.php @@ -419,11 +419,7 @@ class Query } if (isset($cache)) { // 缓存数据 - if (isset($cache['tag'])) { - Cache::tag($cache['tag'])->set($key, $result, $cache['expire']); - } else { - Cache::set($key, $result, $cache['expire']); - } + $this->cacheData($key, $result, $cache); } } else { // 清空查询条件 @@ -491,11 +487,7 @@ class Query } if (isset($cache) && isset($guid)) { // 缓存数据 - if (isset($cache['tag'])) { - Cache::tag($cache['tag'])->set($guid, $result, $cache['expire']); - } else { - Cache::set($guid, $result, $cache['expire']); - } + $this->cacheData($guid, $result, $cache); } } else { // 清空查询条件 @@ -2070,11 +2062,18 @@ class Query // 执行操作 $result = $this->execute($sql, $bind); if ($result) { + $sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null); + $lastInsId = $this->getLastInsID($sequence); + if ($lastInsId) { + $pk = $this->getPk($options); + $data[$pk] = $lastInsId; + } + $options['data'] = $data; $this->trigger('after_insert', $options); - } - if ($getLastInsID) { - $sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null); - return $this->getLastInsID($sequence); + + if ($getLastInsID) { + return $lastInsId; + } } return $result; } @@ -2157,8 +2156,8 @@ class Query $options = $this->parseExpress(); $data = array_merge($options['data'], $data); $pk = $this->getPk($options); - if (isset($options['cache']) && is_string($options['cache'])) { - $key = $options['cache']; + if (isset($options['cache']) && is_string($options['cache']['key'])) { + $key = $options['cache']['key']; } if (empty($options['where'])) { @@ -2187,9 +2186,10 @@ class Query } else { $options['where']['AND'] = $where; } - } elseif (is_string($pk) && isset($options['where']['AND'][$pk]) && is_scalar($options['where']['AND'][$pk])) { - $key = 'think:' . $options['table'] . '|' . $options['where']['AND'][$pk]; + } elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) { + $key = $this->getCacheKey($options['where']['AND'][$pk], $options); } + // 生成UPDATE SQL语句 $sql = $this->builder->update($data, $options); // 获取参数绑定 @@ -2206,6 +2206,13 @@ class Query // 执行操作 $result = '' == $sql ? 0 : $this->execute($sql, $bind); if ($result) { + if (isset($where[$pk])) { + $data[$pk] = $where[$pk]; + } elseif (is_string($pk) && isset($key) && strpos($key, '|')) { + list($a, $val) = explode('|', $key); + $data[$pk] = $val; + } + $options['data'] = $data; $this->trigger('after_update', $options); } return $result; @@ -2278,6 +2285,8 @@ class Query // 获取实际执行的SQL语句 return $this->connection->getRealSql($sql, $bind); } + + $options['data'] = $data; if ($resultSet = $this->trigger('before_select', $options)) { } else { // 执行查询操作 @@ -2291,11 +2300,7 @@ class Query if (isset($cache)) { // 缓存数据集 - if (isset($cache['tag'])) { - Cache::tag($cache['tag'])->set($key, $resultSet, $cache['expire']); - } else { - Cache::set($key, $resultSet, $cache['expire']); - } + $this->cacheData($key, $resultSet, $cache); } } @@ -2339,6 +2344,40 @@ class Query return $resultSet; } + /** + * 缓存数据 + * @access public + * @param string $key 缓存标识 + * @param mixed $data 缓存数据 + * @param array $config 缓存参数 + */ + protected function cacheData($key, $data, $config = []) + { + if (isset($config['tag'])) { + Cache::tag($config['tag'])->set($key, $data, $config['expire']); + } else { + Cache::set($key, $data, $config['expire']); + } + } + + /** + * 生成缓存标识 + * @access public + * @param mixed $value 缓存数据 + * @param array $options 缓存参数 + */ + protected function getCacheKey($value, $options) + { + if (is_scalar($value)) { + $data = $value; + } elseif (is_array($value) && 'eq' == strtolower($value[0])) { + $data = $value[1]; + } + if (isset($data)) { + return 'think:' . $options['table'] . '|' . $data; + } + } + /** * 查找单条记录 * @access public @@ -2358,10 +2397,12 @@ class Query } // 分析查询表达式 $options = $this->parseExpress(); - + $pk = $this->getPk($options); if (!is_null($data)) { // AR模式分析主键条件 $this->parsePkWhere($data, $options); + } elseif (!empty($options['cache']) && true === $options['cache']['key'] && is_string($pk) && isset($options['where']['AND'][$pk])) { + $key = $this->getCacheKey($options['where']['AND'][$pk], $options); } $options['limit'] = 1; @@ -2371,12 +2412,12 @@ class Query $cache = $options['cache']; if (true === $cache['key'] && !is_null($data) && !is_array($data)) { $key = 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data; - } else { + } elseif (!isset($key)) { $key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options)); } $result = Cache::get($key); } - if (!$result) { + if (false === $result) { // 生成查询SQL $sql = $this->builder->select($options); // 获取参数绑定 @@ -2385,56 +2426,61 @@ class Query // 获取实际执行的SQL语句 return $this->connection->getRealSql($sql, $bind); } - + if (is_string($pk)) { + if (!is_array($data)) { + if (isset($key) && strpos($key, '|')) { + list($a, $val) = explode('|', $key); + $item[$pk] = $val; + } else { + $item[$pk] = $data; + } + $data = $item; + } + } + $options['data'] = $data; // 事件回调 if ($result = $this->trigger('before_find', $options)) { } else { // 执行查询 - $result = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']); + $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']); - if ($result instanceof \PDOStatement) { + if ($resultSet instanceof \PDOStatement) { // 返回PDOStatement对象 - return $result; + return $resultSet; } + $result = isset($resultSet[0]) ? $resultSet[0] : null; } if (isset($cache)) { // 缓存数据 - if (isset($cache['tag'])) { - Cache::tag($cache['tag'])->set($key, $result, $cache['expire']); - } else { - Cache::set($key, $result, $cache['expire']); - } + $this->cacheData($key, $result, $cache); } } // 数据处理 - if (!empty($result[0])) { - $data = $result[0]; + if (!empty($result)) { if (!empty($this->model)) { // 返回模型对象 - $model = $this->model; - $data = new $model($data); - $data->isUpdate(true, isset($options['where']['AND']) ? $options['where']['AND'] : null); + $model = $this->model; + $result = new $model($result); + $result->isUpdate(true, isset($options['where']['AND']) ? $options['where']['AND'] : null); // 关联查询 if (!empty($options['relation'])) { - $data->relationQuery($options['relation']); + $result->relationQuery($options['relation']); } // 预载入查询 if (!empty($options['with'])) { - $data->eagerlyResult($data, $options['with']); + $result->eagerlyResult($result, $options['with']); } // 关联统计 if (!empty($options['with_count'])) { - $data->relationCount($data, $options['with_count']); + $result->relationCount($result, $options['with_count']); } } } elseif (!empty($options['fail'])) { $this->throwNotFound($options); - } else { - $data = null; } - return $data; + return $result; } /** @@ -2565,8 +2611,9 @@ class Query { // 分析查询表达式 $options = $this->parseExpress(); - if (isset($options['cache']) && is_string($options['cache'])) { - $key = $options['cache']; + $pk = $this->getPk($options); + if (isset($options['cache']) && is_string($options['cache']['key'])) { + $key = $options['cache']['key']; } if (!is_null($data) && true !== $data) { @@ -2576,6 +2623,8 @@ class Query } // AR模式分析主键条件 $this->parsePkWhere($data, $options); + } elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) { + $key = $this->getCacheKey($options['where']['AND'][$pk], $options); } if (true !== $data && empty($options['where'])) { @@ -2599,6 +2648,12 @@ class Query // 执行操作 $result = $this->execute($sql, $bind); if ($result) { + if (!is_array($data) && is_string($pk) && isset($key) && strpos($key, '|')) { + list($a, $val) = explode('|', $key); + $item[$pk] = $val; + $data = $item; + } + $options['data'] = $data; $this->trigger('after_delete', $options); } return $result; @@ -2711,15 +2766,15 @@ class Query * 触发事件 * @access protected * @param string $event 事件名 - * @param mixed $options 当前查询参数 + * @param mixed $params 额外参数 * @return bool */ - protected function trigger($event, $options = []) + protected function trigger($event, $params = []) { $result = false; if (isset(self::$event[$event])) { $callback = self::$event[$event]; - $result = call_user_func_array($callback, [$options, $this]); + $result = call_user_func_array($callback, [$params, $this]); } return $result; } diff --git a/core/library/think/db/connector/Mysql.php b/core/library/think/db/connector/Mysql.php index 0a14e48e..0081fb2e 100644 --- a/core/library/think/db/connector/Mysql.php +++ b/core/library/think/db/connector/Mysql.php @@ -129,4 +129,18 @@ class Mysql extends Connection { return true; } + + /** + * 是否断线 + * @access protected + * @param \PDOException $e 异常对象 + * @return bool + */ + protected function isBreak($e) + { + if (false !== stripos($e->getMessage(), 'server has gone away')) { + return true; + } + return false; + } } diff --git a/core/library/think/model/relation/BelongsToMany.php b/core/library/think/model/relation/BelongsToMany.php index c85a8c0c..128287e0 100644 --- a/core/library/think/model/relation/BelongsToMany.php +++ b/core/library/think/model/relation/BelongsToMany.php @@ -54,7 +54,7 @@ class BelongsToMany extends Relation $localKey = $this->localKey; $middle = $this->middle; if ($closure) { - call_user_func_array($closure, [& $this->query]); + call_user_func_array($closure, [ & $this->query]); } // 关联查询 $pk = $this->parent->getPk(); @@ -174,8 +174,8 @@ class BelongsToMany extends Relation return $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, [ 'pivot.' . $this->localKey => [ 'exp', - '=' . $this->parent->getTable() . '.' . $this->parent->getPk() - ] + '=' . $this->parent->getTable() . '.' . $this->parent->getPk(), + ], ])->fetchSql()->count(); } @@ -271,7 +271,7 @@ class BelongsToMany extends Relation * @access public * @param mixed $data 数据 可以使用数组、关联模型对象 或者 关联对象的主键 * @param array $pivot 中间表额外数据 - * @return int + * @return array|Pivot * @throws Exception */ public function attach($data, $pivot = []) @@ -301,7 +301,12 @@ class BelongsToMany extends Relation $ids = (array) $id; foreach ($ids as $id) { $pivot[$this->foreignKey] = $id; - $result = $this->query->table($this->middle)->insert($pivot, true); + $this->query->table($this->middle)->insert($pivot, true); + $result[] = new Pivot($pivot, $this->middle); + } + if (count($result) == 1) { + // 返回中间表模型对象 + $result = $result[0]; } return $result; } else { diff --git a/core/library/think/model/relation/HasMany.php b/core/library/think/model/relation/HasMany.php index 3094bb55..9bcdcead 100644 --- a/core/library/think/model/relation/HasMany.php +++ b/core/library/think/model/relation/HasMany.php @@ -45,7 +45,7 @@ class HasMany extends Relation public function getRelation($subRelation = '', $closure = null) { if ($closure) { - call_user_func_array($closure, [& $this->query]); + call_user_func_array($closure, [ & $this->query]); } return $this->relation($subRelation)->select(); } @@ -125,7 +125,7 @@ class HasMany extends Relation $count = 0; if (isset($result->$localKey)) { if ($closure) { - call_user_func_array($closure, [& $this->query]); + call_user_func_array($closure, [ & $this->query]); } $count = $this->query->where([$this->foreignKey => $result->$localKey])->count(); } @@ -141,14 +141,14 @@ class HasMany extends Relation public function getRelationCountQuery($closure) { if ($closure) { - call_user_func_array($closure, [& $this->query]); + call_user_func_array($closure, [ & $this->query]); } return $this->query->where([ $this->foreignKey => [ 'exp', - '=' . $this->parent->getTable() . '.' . $this->parent->getPk() - ] + '=' . $this->parent->getTable() . '.' . $this->parent->getPk(), + ], ])->fetchSql()->count(); } @@ -167,7 +167,7 @@ class HasMany extends Relation $foreignKey = $this->foreignKey; // 预载入关联查询 支持嵌套预载入 if ($closure) { - call_user_func_array($closure, [& $model]); + call_user_func_array($closure, [ & $model]); } $list = $model->where($where)->with($subRelation)->select(); @@ -217,13 +217,14 @@ class HasMany extends Relation * @param string $operator 比较操作符 * @param integer $count 个数 * @param string $id 关联表的统计字段 + * @param string $joinType JOIN类型 * @return Query */ - public function has($operator = '>=', $count = 1, $id = '*') + public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER') { $table = $this->query->getTable(); return $this->parent->db()->alias('a') - ->join($table . ' b', 'a.' . $this->localKey . '=b.' . $this->foreignKey, $this->joinType) + ->join($table . ' b', 'a.' . $this->localKey . '=b.' . $this->foreignKey, $joinType) ->group('b.' . $this->foreignKey) ->having('count(' . $id . ')' . $operator . $count); } diff --git a/core/library/traits/controller/Jump.php b/core/library/traits/controller/Jump.php index 51f4281f..6e6f2dec 100644 --- a/core/library/traits/controller/Jump.php +++ b/core/library/traits/controller/Jump.php @@ -131,16 +131,17 @@ trait Jump * @param string $url 跳转的URL表达式 * @param array|integer $params 其它URL参数 * @param integer $code http code + * @param array $with 隐式传参 * @return void */ - protected function redirect($url, $params = [], $code = 302) + protected function redirect($url, $params = [], $code = 302, $with = []) { $response = new Redirect($url); if (is_integer($params)) { $code = $params; $params = []; } - $response->code($code)->params($params); + $response->code($code)->params($params)->with($with); throw new HttpResponseException($response); } diff --git a/core/library/traits/model/SoftDelete.php b/core/library/traits/model/SoftDelete.php index 8781544f..720b6e88 100644 --- a/core/library/traits/model/SoftDelete.php +++ b/core/library/traits/model/SoftDelete.php @@ -42,7 +42,7 @@ trait SoftDelete { $model = new static(); $field = $model->getDeleteTimeField(true); - return $model->db(false)->where($field, 'exp', 'is not null'); + return $model->db(false)->whereNotNull($field); } /** @@ -129,7 +129,7 @@ trait SoftDelete protected function base($query) { $field = $this->getDeleteTimeField(true); - $query->where($field, 'null'); + $query->whereNull($field); } /**