更新tp5内核
This commit is contained in:
+165
-77
@@ -2,7 +2,7 @@
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace think;
|
||||
|
||||
use BadMethodCallException;
|
||||
use InvalidArgumentException;
|
||||
use think\db\Query;
|
||||
use think\exception\ValidateException;
|
||||
@@ -56,6 +57,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
protected $pk;
|
||||
// 数据表字段信息 留空则自动获取
|
||||
protected $field = [];
|
||||
// 数据排除字段
|
||||
protected $except = [];
|
||||
// 数据废弃字段
|
||||
protected $disuse = [];
|
||||
// 只读字段
|
||||
protected $readonly = [];
|
||||
// 显示属性
|
||||
@@ -89,6 +94,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
protected $type = [];
|
||||
// 是否为更新数据
|
||||
protected $isUpdate = false;
|
||||
// 是否强制更新所有数据
|
||||
protected $force = false;
|
||||
// 更新条件
|
||||
protected $updateWhere;
|
||||
// 验证失败是否抛出异常
|
||||
@@ -121,6 +128,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
} else {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
if ($this->disuse) {
|
||||
// 废弃字段
|
||||
foreach ((array) $this->disuse as $key) {
|
||||
if (array_key_exists($key, $this->data)) {
|
||||
unset($this->data[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 记录原始数据
|
||||
$this->origin = $this->data;
|
||||
|
||||
@@ -261,7 +278,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
public function setParent($model)
|
||||
{
|
||||
$this->parent = $model;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -336,6 +352,18 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新是否强制写入数据 而不做比较
|
||||
* @access public
|
||||
* @param bool $force
|
||||
* @return $this
|
||||
*/
|
||||
public function force($force = true)
|
||||
{
|
||||
$this->force = $force;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改器 设置数据对象值
|
||||
* @access public
|
||||
@@ -353,7 +381,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 检测修改器
|
||||
$method = 'set' . Loader::parseName($name, 1) . 'Attr';
|
||||
if (method_exists($this, $method)) {
|
||||
$value = $this->$method($value, array_merge($this->data, $data));
|
||||
$value = $this->$method($value, array_merge($this->data, $data), $this->relation);
|
||||
} elseif (isset($this->type[$name])) {
|
||||
// 类型转换
|
||||
$value = $this->writeTransform($value, $this->type[$name]);
|
||||
@@ -532,7 +560,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 检测属性获取器
|
||||
$method = 'get' . Loader::parseName($name, 1) . 'Attr';
|
||||
if (method_exists($this, $method)) {
|
||||
$value = $this->$method($value, $this->data);
|
||||
$value = $this->$method($value, $this->data, $this->relation);
|
||||
} elseif (isset($this->type[$name])) {
|
||||
// 类型转换
|
||||
$value = $this->readTransform($value, $this->type[$name]);
|
||||
@@ -567,6 +595,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* @access public
|
||||
* @param Relation $modelRelation 模型关联对象
|
||||
* @return mixed
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
protected function getRelationData(Relation $modelRelation)
|
||||
{
|
||||
@@ -574,7 +603,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$value = $this->parent;
|
||||
} else {
|
||||
// 首先获取关联数据
|
||||
$value = $modelRelation->getRelation();
|
||||
if (method_exists($modelRelation, 'getRelation')) {
|
||||
$value = $modelRelation->getRelation();
|
||||
} else {
|
||||
throw new BadMethodCallException('method not exists:' . get_class($modelRelation) . '-> getRelation');
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
@@ -686,7 +719,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
if (isset($this->data[$key])) {
|
||||
throw new Exception('bind attr has exists:' . $key);
|
||||
} else {
|
||||
$this->data[$key] = $model->$attr;
|
||||
$this->data[$key] = $model->getAttr($attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -820,7 +853,29 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$relation = $this->getAttr($key);
|
||||
$item[$key] = $relation->append([$attr])->toArray();
|
||||
} else {
|
||||
$item[$name] = $this->getAttr($name);
|
||||
$relation = Loader::parseName($name, 1, false);
|
||||
if (method_exists($this, $relation)) {
|
||||
$modelRelation = $this->$relation();
|
||||
$value = $this->getRelationData($modelRelation);
|
||||
|
||||
if (method_exists($modelRelation, 'getBindAttr')) {
|
||||
$bindAttr = $modelRelation->getBindAttr();
|
||||
if ($bindAttr) {
|
||||
foreach ($bindAttr as $key => $attr) {
|
||||
$key = is_numeric($key) ? $attr : $key;
|
||||
if (isset($this->data[$key])) {
|
||||
throw new Exception('bind attr has exists:' . $key);
|
||||
} else {
|
||||
$item[$key] = $value ? $value->getAttr($attr) : null;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$item[$name] = $value;
|
||||
} else {
|
||||
$item[$name] = $this->getAttr($name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -927,6 +982,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public function save($data = [], $where = [], $sequence = null)
|
||||
{
|
||||
if (is_string($data)) {
|
||||
$sequence = $data;
|
||||
$data = [];
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
// 数据自动验证
|
||||
if (!$this->validateData($data)) {
|
||||
@@ -937,7 +997,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$this->setAttr($key, $value, $data);
|
||||
}
|
||||
if (!empty($where)) {
|
||||
$this->isUpdate = true;
|
||||
$this->isUpdate = true;
|
||||
$this->updateWhere = $where;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1009,12 +1070,17 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
}
|
||||
|
||||
if (is_string($pk) && isset($data[$pk])) {
|
||||
if (!isset($where[$pk])) {
|
||||
unset($where);
|
||||
$where[$pk] = $data[$pk];
|
||||
$array = [];
|
||||
|
||||
foreach ((array) $pk as $key) {
|
||||
if (isset($data[$key])) {
|
||||
$array[$key] = $data[$key];
|
||||
unset($data[$key]);
|
||||
}
|
||||
unset($data[$pk]);
|
||||
}
|
||||
|
||||
if (!empty($array)) {
|
||||
$where = $array;
|
||||
}
|
||||
|
||||
// 检测字段
|
||||
@@ -1056,16 +1122,17 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 检测字段
|
||||
$allowFields = $this->checkAllowField(array_merge($this->auto, $this->insert));
|
||||
if (!empty($allowFields)) {
|
||||
$result = $this->getQuery()->strict(false)->field($allowFields)->insert($this->data);
|
||||
$result = $this->getQuery()->strict(false)->field($allowFields)->insert($this->data, false, false, $sequence);
|
||||
} else {
|
||||
$result = $this->getQuery()->insert($this->data);
|
||||
$result = $this->getQuery()->insert($this->data, false, false, $sequence);
|
||||
}
|
||||
|
||||
// 获取自动增长主键
|
||||
if ($result && is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) {
|
||||
$insertId = $this->getQuery()->getLastInsID($sequence);
|
||||
if ($insertId) {
|
||||
$this->data[$pk] = $insertId;
|
||||
if ($result && $insertId = $this->getQuery()->getLastInsID($sequence)) {
|
||||
foreach ((array) $pk as $key) {
|
||||
if (!isset($this->data[$key]) || '' == $this->data[$key]) {
|
||||
$this->data[$key] = $insertId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1094,19 +1161,26 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
|
||||
protected function checkAllowField($auto = [])
|
||||
{
|
||||
if (!empty($this->field)) {
|
||||
if (!empty($this->origin)) {
|
||||
$this->field = array_keys($this->origin);
|
||||
$field = $this->field;
|
||||
} elseif (true === $this->field) {
|
||||
$this->field = $this->getQuery()->getTableInfo('', 'fields');
|
||||
$field = $this->field;
|
||||
} else {
|
||||
$field = array_merge($this->field, $auto);
|
||||
if (true === $this->field) {
|
||||
$this->field = $this->getQuery()->getTableInfo('', 'fields');
|
||||
$field = $this->field;
|
||||
} elseif (!empty($this->field)) {
|
||||
$field = array_merge($this->field, $auto);
|
||||
if ($this->autoWriteTimestamp) {
|
||||
array_push($field, $this->createTime, $this->updateTime);
|
||||
}
|
||||
} elseif (!empty($this->except)) {
|
||||
$fields = $this->getQuery()->getTableInfo('', 'fields');
|
||||
$field = array_diff($fields, (array) $this->except);
|
||||
$this->field = $field;
|
||||
} else {
|
||||
$field = [];
|
||||
}
|
||||
|
||||
if ($this->disuse) {
|
||||
// 废弃字段
|
||||
$field = array_diff($field, (array) $this->disuse);
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
@@ -1132,12 +1206,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public function getChangedData()
|
||||
{
|
||||
$data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
|
||||
if ((empty($b) || empty($b)) && $a !== $b) {
|
||||
return 1;
|
||||
}
|
||||
return is_object($a) || $a != $b ? 1 : 0;
|
||||
});
|
||||
if ($this->force) {
|
||||
$data = $this->data;
|
||||
} else {
|
||||
$data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
|
||||
if ((empty($a) || empty($b)) && $a !== $b) {
|
||||
return 1;
|
||||
}
|
||||
return is_object($a) || $a != $b ? 1 : 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (!empty($this->readonly)) {
|
||||
// 只读字段不允许更新
|
||||
@@ -1162,16 +1240,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public function setInc($field, $step = 1, $lazyTime = 0)
|
||||
{
|
||||
// 删除条件
|
||||
$pk = $this->getPk();
|
||||
|
||||
if (is_string($pk) && isset($this->data[$pk])) {
|
||||
$where = [$pk => $this->data[$pk]];
|
||||
} elseif (!empty($this->updateWhere)) {
|
||||
$where = $this->updateWhere;
|
||||
} else {
|
||||
$where = null;
|
||||
}
|
||||
// 更新条件
|
||||
$where = $this->getWhere();
|
||||
|
||||
$result = $this->getQuery()->where($where)->setInc($field, $step, $lazyTime);
|
||||
if (true !== $result) {
|
||||
@@ -1191,6 +1261,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setDec($field, $step = 1, $lazyTime = 0)
|
||||
{
|
||||
// 更新条件
|
||||
$where = $this->getWhere();
|
||||
$result = $this->getQuery()->where($where)->setDec($field, $step, $lazyTime);
|
||||
if (true !== $result) {
|
||||
$this->data[$field] -= $step;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取更新条件
|
||||
* @access protected
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getWhere()
|
||||
{
|
||||
// 删除条件
|
||||
$pk = $this->getPk();
|
||||
@@ -1202,13 +1289,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
} else {
|
||||
$where = null;
|
||||
}
|
||||
|
||||
$result = $this->getQuery()->where($where)->setDec($field, $step, $lazyTime);
|
||||
if (true !== $result) {
|
||||
$this->data[$field] -= $step;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $where;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1240,14 +1321,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$auto = true;
|
||||
}
|
||||
foreach ($dataSet as $key => $data) {
|
||||
if (!empty($auto) && isset($data[$pk])) {
|
||||
if ($this->isUpdate || (!empty($auto) && isset($data[$pk]))) {
|
||||
$result[$key] = self::update($data, [], $this->field);
|
||||
} else {
|
||||
$result[$key] = self::create($data, $this->field);
|
||||
}
|
||||
}
|
||||
$db->commit();
|
||||
return $result;
|
||||
return $this->toCollection($result);
|
||||
} catch (\Exception $e) {
|
||||
$db->rollback();
|
||||
throw $e;
|
||||
@@ -1257,7 +1338,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
/**
|
||||
* 设置允许写入的字段
|
||||
* @access public
|
||||
* @param mixed $field 允许写入的字段 如果为true只允许写入数据表字段
|
||||
* @param string|array $field 允许写入的字段 如果为true只允许写入数据表字段
|
||||
* @return $this
|
||||
*/
|
||||
public function allowField($field)
|
||||
@@ -1269,6 +1350,21 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置排除写入的字段
|
||||
* @access public
|
||||
* @param string|array $field 排除允许写入的字段
|
||||
* @return $this
|
||||
*/
|
||||
public function except($field)
|
||||
{
|
||||
if (is_string($field)) {
|
||||
$field = explode(',', $field);
|
||||
}
|
||||
$this->except = $field;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置只读字段
|
||||
* @access public
|
||||
@@ -1336,14 +1432,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
|
||||
// 删除条件
|
||||
$pk = $this->getPk();
|
||||
if (is_string($pk) && isset($this->data[$pk])) {
|
||||
$where = [$pk => $this->data[$pk]];
|
||||
} elseif (!empty($this->updateWhere)) {
|
||||
$where = $this->updateWhere;
|
||||
} else {
|
||||
$where = null;
|
||||
}
|
||||
$where = $this->getWhere();
|
||||
|
||||
// 删除当前模型数据
|
||||
$result = $this->getQuery()->where($where)->delete();
|
||||
@@ -1614,14 +1703,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
{
|
||||
$model = new static();
|
||||
$query = $model->db();
|
||||
if (is_array($data) && key($data) !== 0) {
|
||||
if (empty($data) && 0 !== $data) {
|
||||
return 0;
|
||||
} elseif (is_array($data) && key($data) !== 0) {
|
||||
$query->where($data);
|
||||
$data = null;
|
||||
} elseif ($data instanceof \Closure) {
|
||||
call_user_func_array($data, [ & $query]);
|
||||
$data = null;
|
||||
} elseif (empty($data) && 0 !== $data) {
|
||||
return 0;
|
||||
}
|
||||
$resultSet = $query->select($data);
|
||||
$count = 0;
|
||||
@@ -1668,7 +1757,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* 设置是否使用全局查询范围
|
||||
* @param bool $use 是否启用全局查询范围
|
||||
* @access public
|
||||
* @return Model
|
||||
* @return Query
|
||||
*/
|
||||
public static function useGlobalScope($use)
|
||||
{
|
||||
@@ -1697,13 +1786,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
/**
|
||||
* 根据关联条件查询当前模型
|
||||
* @access public
|
||||
* @param string $relation 关联方法名
|
||||
* @param mixed $where 查询条件(数组或者闭包)
|
||||
* @param string $relation 关联方法名
|
||||
* @param mixed $where 查询条件(数组或者闭包)
|
||||
* @param mixed $fields 字段
|
||||
* @return Relation|Query
|
||||
*/
|
||||
public static function hasWhere($relation, $where = [])
|
||||
public static function hasWhere($relation, $where = [], $fields = null)
|
||||
{
|
||||
return (new static())->$relation()->hasWhere($where);
|
||||
return (new static())->$relation()->hasWhere($where, $fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1860,7 +1950,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* @access public
|
||||
* @param string $model 模型名
|
||||
* @param string $foreignKey 关联外键
|
||||
* @param string $localKey 关联主键
|
||||
* @param string $localKey 当前模型主键
|
||||
* @param array $alias 别名定义(已经废弃)
|
||||
* @param string $joinType JOIN类型
|
||||
* @return HasOne
|
||||
@@ -1900,7 +1990,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* @access public
|
||||
* @param string $model 模型名
|
||||
* @param string $foreignKey 关联外键
|
||||
* @param string $localKey 关联主键
|
||||
* @param string $localKey 当前模型主键
|
||||
* @return HasMany
|
||||
*/
|
||||
public function hasMany($model, $foreignKey = '', $localKey = '')
|
||||
@@ -1919,7 +2009,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* @param string $through 中间模型名
|
||||
* @param string $foreignKey 关联外键
|
||||
* @param string $throughKey 关联外键
|
||||
* @param string $localKey 关联主键
|
||||
* @param string $localKey 当前模型主键
|
||||
* @return HasManyThrough
|
||||
*/
|
||||
public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '')
|
||||
@@ -1969,7 +2059,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$morph = Loader::parseName($trace[1]['function']);
|
||||
}
|
||||
$type = $type ?: Loader::parseName($this->name);
|
||||
$type = $type ?: get_class($this);
|
||||
if (is_array($morph)) {
|
||||
list($morphType, $foreignKey) = $morph;
|
||||
} else {
|
||||
@@ -1995,7 +2085,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$morph = Loader::parseName($trace[1]['function']);
|
||||
}
|
||||
$type = $type ?: Loader::parseName($this->name);
|
||||
$type = $type ?: get_class($this);
|
||||
if (is_array($morph)) {
|
||||
list($morphType, $foreignKey) = $morph;
|
||||
} else {
|
||||
@@ -2033,7 +2123,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
public function __call($method, $args)
|
||||
{
|
||||
$query = $this->db(true, false);
|
||||
|
||||
if (method_exists($this, 'scope' . $method)) {
|
||||
// 动态调用命名范围
|
||||
$method = 'scope' . $method;
|
||||
@@ -2049,7 +2138,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
{
|
||||
$model = new static();
|
||||
$query = $model->db();
|
||||
|
||||
if (method_exists($model, 'scope' . $method)) {
|
||||
// 动态调用命名范围
|
||||
$method = 'scope' . $method;
|
||||
|
||||
Reference in New Issue
Block a user