更新内核,API接口开发的一些尝试,后期会增加API接口开发这块
This commit is contained in:
@@ -22,6 +22,7 @@ use think\model\relation\HasMany;
|
||||
use think\model\relation\HasManyThrough;
|
||||
use think\model\relation\HasOne;
|
||||
use think\model\relation\MorphMany;
|
||||
use think\model\relation\MorphOne;
|
||||
use think\model\relation\MorphTo;
|
||||
|
||||
/**
|
||||
@@ -31,10 +32,12 @@ use think\model\relation\MorphTo;
|
||||
*/
|
||||
abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
{
|
||||
// 数据库对象池
|
||||
// 数据库查询对象池
|
||||
protected static $links = [];
|
||||
// 数据库配置
|
||||
protected $connection = [];
|
||||
// 父关联模型对象
|
||||
protected $parent;
|
||||
// 数据库查询对象
|
||||
protected $query;
|
||||
// 当前模型名称
|
||||
@@ -63,8 +66,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
protected $append = [];
|
||||
// 数据信息
|
||||
protected $data = [];
|
||||
// 记录改变字段
|
||||
protected $change = [];
|
||||
// 原始数据
|
||||
protected $origin = [];
|
||||
// 关联模型
|
||||
protected $relation = [];
|
||||
|
||||
// 保存自动完成列表
|
||||
protected $auto = [];
|
||||
@@ -86,8 +91,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
protected $isUpdate = false;
|
||||
// 更新条件
|
||||
protected $updateWhere;
|
||||
// 当前执行的关联对象
|
||||
protected $relation;
|
||||
// 验证失败是否抛出异常
|
||||
protected $failException = false;
|
||||
// 全局查询范围
|
||||
@@ -98,8 +101,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
protected $resultSetType;
|
||||
// 关联自动写入
|
||||
protected $relationWrite;
|
||||
//
|
||||
protected static $db;
|
||||
|
||||
/**
|
||||
* 初始化过的模型.
|
||||
@@ -120,9 +121,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
} else {
|
||||
$this->data = $data;
|
||||
}
|
||||
// 记录原始数据
|
||||
$this->origin = $this->data;
|
||||
|
||||
// 当前类名
|
||||
$this->class = get_class($this);
|
||||
$this->class = get_called_class();
|
||||
|
||||
if (empty($this->name)) {
|
||||
// 当前模型名
|
||||
@@ -136,63 +139,94 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
|
||||
if (is_null($this->autoWriteTimestamp)) {
|
||||
// 自动写入时间戳
|
||||
$this->autoWriteTimestamp = $this->db(false)->getConfig('auto_timestamp');
|
||||
$this->autoWriteTimestamp = $this->getQuery()->getConfig('auto_timestamp');
|
||||
}
|
||||
|
||||
if (is_null($this->dateFormat)) {
|
||||
// 设置时间戳格式
|
||||
$this->dateFormat = $this->db(false)->getConfig('datetime_format');
|
||||
$this->dateFormat = $this->getQuery()->getConfig('datetime_format');
|
||||
}
|
||||
|
||||
if (is_null($this->resultSetType)) {
|
||||
$this->resultSetType = $this->db(false)->getConfig('resultset_type');
|
||||
$this->resultSetType = $this->getQuery()->getConfig('resultset_type');
|
||||
}
|
||||
// 执行初始化操作
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模型的数据库查询对象
|
||||
* @access public
|
||||
* @param bool $baseQuery 是否调用全局查询范围
|
||||
* 创建模型的查询对象
|
||||
* @access protected
|
||||
* @return Query
|
||||
*/
|
||||
public function db($baseQuery = true)
|
||||
protected function buildQuery()
|
||||
{
|
||||
$model = $this->class;
|
||||
if (!isset(self::$links[$model])) {
|
||||
// 合并数据库配置
|
||||
if (!empty($this->connection)) {
|
||||
if (is_array($this->connection)) {
|
||||
$connection = array_merge(Config::get('database'), $this->connection);
|
||||
} else {
|
||||
$connection = $this->connection;
|
||||
}
|
||||
// 合并数据库配置
|
||||
if (!empty($this->connection)) {
|
||||
if (is_array($this->connection)) {
|
||||
$connection = array_merge(Config::get('database'), $this->connection);
|
||||
} else {
|
||||
$connection = [];
|
||||
$connection = $this->connection;
|
||||
}
|
||||
// 设置当前模型 确保查询返回模型对象
|
||||
$query = Db::connect($connection)->getQuery($model, $this->query);
|
||||
|
||||
// 设置当前数据表和模型名
|
||||
if (!empty($this->table)) {
|
||||
$query->setTable($this->table);
|
||||
} else {
|
||||
$query->name($this->name);
|
||||
}
|
||||
|
||||
if (!empty($this->pk)) {
|
||||
$query->pk($this->pk);
|
||||
}
|
||||
|
||||
self::$links[$model] = $query;
|
||||
} else {
|
||||
$connection = [];
|
||||
}
|
||||
|
||||
$con = Db::connect($connection);
|
||||
// 设置当前模型 确保查询返回模型对象
|
||||
$queryClass = $this->query ?: $con->getConfig('query');
|
||||
$query = new $queryClass($con, $this->class);
|
||||
|
||||
// 设置当前数据表和模型名
|
||||
if (!empty($this->table)) {
|
||||
$query->setTable($this->table);
|
||||
} else {
|
||||
$query->name($this->name);
|
||||
}
|
||||
|
||||
if (!empty($this->pk)) {
|
||||
$query->pk($this->pk);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模型的查询对象
|
||||
* @access public
|
||||
* @param bool $buildNewQuery 创建新的查询对象
|
||||
* @return Query
|
||||
*/
|
||||
public function getQuery($buildNewQuery = false)
|
||||
{
|
||||
if ($buildNewQuery) {
|
||||
return $this->buildQuery();
|
||||
} elseif (!isset(self::$links[$this->class])) {
|
||||
// 创建模型查询对象
|
||||
self::$links[$this->class] = $this->buildQuery();
|
||||
}
|
||||
|
||||
return self::$links[$this->class];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模型的数据库查询对象
|
||||
* @access public
|
||||
* @param bool $useBaseQuery 是否调用全局查询范围
|
||||
* @param bool $buildNewQuery 创建新的查询对象
|
||||
* @return Query
|
||||
*/
|
||||
public function db($useBaseQuery = true, $buildNewQuery = true)
|
||||
{
|
||||
$query = $this->getQuery($buildNewQuery);
|
||||
|
||||
// 全局作用域
|
||||
if ($baseQuery && method_exists($this, 'base')) {
|
||||
call_user_func_array([$this, 'base'], [ & self::$links[$model]]);
|
||||
if ($useBaseQuery && method_exists($this, 'base')) {
|
||||
call_user_func_array([$this, 'base'], [ & $query]);
|
||||
}
|
||||
|
||||
// 返回当前模型的数据库查询对象
|
||||
return self::$links[$model];
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,6 +252,29 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置父关联对象
|
||||
* @access public
|
||||
* @param Model $model 模型对象
|
||||
* @return $this
|
||||
*/
|
||||
public function setParent($model)
|
||||
{
|
||||
$this->parent = $model;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取父关联对象
|
||||
* @access public
|
||||
* @return Model
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据对象值
|
||||
* @access public
|
||||
@@ -260,6 +317,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return $this->data;
|
||||
} elseif (array_key_exists($name, $this->data)) {
|
||||
return $this->data[$name];
|
||||
} elseif (array_key_exists($name, $this->relation)) {
|
||||
return $this->relation[$name];
|
||||
} else {
|
||||
throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
|
||||
}
|
||||
@@ -282,26 +341,48 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 检测修改器
|
||||
$method = 'set' . Loader::parseName($name, 1) . 'Attr';
|
||||
if (method_exists($this, $method)) {
|
||||
$value = $this->$method($value, array_merge($data, $this->data));
|
||||
$value = $this->$method($value, array_merge($this->data, $data));
|
||||
} elseif (isset($this->type[$name])) {
|
||||
// 类型转换
|
||||
$value = $this->writeTransform($value, $this->type[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
// 标记字段更改
|
||||
if (!isset($this->data[$name])) {
|
||||
$this->change[] = $name;
|
||||
} elseif (is_scalar($value) && is_scalar($this->data[$name]) && 0 !== strcmp($this->data[$name], $value)) {
|
||||
$this->change[] = $name;
|
||||
} elseif (!is_object($value) && $value != $this->data[$name]) {
|
||||
$this->change[] = $name;
|
||||
}
|
||||
// 设置数据对象属性
|
||||
$this->data[$name] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前模型的关联模型数据
|
||||
* @access public
|
||||
* @param string $name 关联方法名
|
||||
* @return mixed
|
||||
*/
|
||||
public function getRelation($name = null)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
return $this->relation;
|
||||
} elseif (array_key_exists($name, $this->relation)) {
|
||||
return $this->relation[$name];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置关联数据对象值
|
||||
* @access public
|
||||
* @param string $name 属性名
|
||||
* @param mixed $value 属性值
|
||||
* @return $this
|
||||
*/
|
||||
public function setRelation($name, $value)
|
||||
{
|
||||
$this->relation[$name] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动写入时间戳
|
||||
* @access public
|
||||
@@ -319,12 +400,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
case 'datetime':
|
||||
case 'date':
|
||||
$format = !empty($param) ? $param : $this->dateFormat;
|
||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $format);
|
||||
$value = $this->formatDateTime(time(), $format);
|
||||
break;
|
||||
case 'timestamp':
|
||||
case 'integer':
|
||||
default:
|
||||
$value = $_SERVER['REQUEST_TIME'];
|
||||
$value = time();
|
||||
break;
|
||||
}
|
||||
} elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [
|
||||
@@ -333,9 +414,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
'timestamp',
|
||||
])
|
||||
) {
|
||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $this->dateFormat);
|
||||
$value = $this->formatDateTime(time(), $this->dateFormat);
|
||||
} else {
|
||||
$value = $this->formatDateTime($_SERVER['REQUEST_TIME'], $this->dateFormat, true);
|
||||
$value = $this->formatDateTime(time(), $this->dateFormat, true);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
@@ -367,6 +448,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
protected function writeTransform($value, $type)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($type)) {
|
||||
list($type, $param) = $type;
|
||||
} elseif (strpos($type, ':')) {
|
||||
@@ -451,14 +536,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$value = $this->formatDateTime($value, $this->dateFormat);
|
||||
}
|
||||
} elseif ($notFound) {
|
||||
$method = Loader::parseName($name, 1, false);
|
||||
if (method_exists($this, $method) && $this->$method() instanceof Relation) {
|
||||
// 清空之前的查询参数
|
||||
$this->$method()->removeOption();
|
||||
$relation = Loader::parseName($name, 1, false);
|
||||
if (method_exists($this, $relation)) {
|
||||
$modelRelation = $this->$relation();
|
||||
// 不存在该字段 获取关联数据
|
||||
$value = $this->$method()->getRelation();
|
||||
$value = $this->getRelationData($modelRelation);
|
||||
// 保存关联对象值
|
||||
$this->data[$name] = $value;
|
||||
$this->relation[$name] = $value;
|
||||
} else {
|
||||
throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
|
||||
}
|
||||
@@ -466,6 +550,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取关联模型数据
|
||||
* @access public
|
||||
* @param Relation $modelRelation 模型关联对象
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getRelationData(Relation $modelRelation)
|
||||
{
|
||||
if ($this->parent && get_class($this->parent) == $modelRelation->getModel()) {
|
||||
$value = $this->parent;
|
||||
} else {
|
||||
// 首先获取关联数据
|
||||
$value = $modelRelation->getRelation();
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据读取 类型转换
|
||||
* @access public
|
||||
@@ -475,6 +576,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
protected function readTransform($value, $type)
|
||||
{
|
||||
if (is_null($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_array($type)) {
|
||||
list($type, $param) = $type;
|
||||
} elseif (strpos($type, ':')) {
|
||||
@@ -553,14 +658,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
if (is_string($append)) {
|
||||
$append = explode(',', $append);
|
||||
}
|
||||
$model = $this->getAttr($relation);
|
||||
|
||||
$relation = Loader::parseName($relation, 1, false);
|
||||
|
||||
// 获取关联数据
|
||||
if (isset($this->relation[$relation])) {
|
||||
$model = $this->relation[$relation];
|
||||
} else {
|
||||
$model = $this->getRelationData($this->$relation());
|
||||
}
|
||||
|
||||
if ($model instanceof Model) {
|
||||
foreach ($append as $key => $attr) {
|
||||
$key = is_numeric($key) ? $attr : $key;
|
||||
if ($this->__isset($key)) {
|
||||
if (isset($this->data[$key])) {
|
||||
throw new Exception('bind attr has exists:' . $key);
|
||||
} else {
|
||||
$this->setAttr($key, $model->$attr);
|
||||
$this->data[$key] = $model->$attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -653,15 +767,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$item = [];
|
||||
$visible = [];
|
||||
$hidden = [];
|
||||
|
||||
$data = array_merge($this->data, $this->relation);
|
||||
|
||||
// 过滤属性
|
||||
if (!empty($this->visible)) {
|
||||
$array = $this->parseAttr($this->visible, $visible);
|
||||
$data = array_intersect_key($this->data, array_flip($array));
|
||||
$data = array_intersect_key($data, array_flip($array));
|
||||
} elseif (!empty($this->hidden)) {
|
||||
$array = $this->parseAttr($this->hidden, $hidden, false);
|
||||
$data = array_diff_key($this->data, array_flip($array));
|
||||
} else {
|
||||
$data = $this->data;
|
||||
$data = array_diff_key($data, array_flip($array));
|
||||
}
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
@@ -672,7 +787,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 关联模型数据集
|
||||
$arr = [];
|
||||
foreach ($val as $k => $value) {
|
||||
$arr[$k] = $this->subToArray($value, $visible, $hidden, $k);
|
||||
$arr[$k] = $this->subToArray($value, $visible, $hidden, $key);
|
||||
}
|
||||
$item[$key] = $arr;
|
||||
} else {
|
||||
@@ -754,10 +869,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
public function getPk($name = '')
|
||||
{
|
||||
if (!empty($name)) {
|
||||
$table = $this->db(false)->getTable($name);
|
||||
return $this->db(false)->getPk($table);
|
||||
$table = $this->getQuery()->getTable($name);
|
||||
return $this->getQuery()->getPk($table);
|
||||
} elseif (empty($this->pk)) {
|
||||
$this->pk = $this->db(false)->getPk();
|
||||
$this->pk = $this->getQuery()->getPk();
|
||||
}
|
||||
return $this->pk;
|
||||
}
|
||||
@@ -807,31 +922,23 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
if (!empty($this->relationWrite)) {
|
||||
$relation = [];
|
||||
foreach ($this->relationWrite as $key => $name) {
|
||||
if (!is_numeric($key)) {
|
||||
$relation[$key] = [];
|
||||
foreach ($name as $val) {
|
||||
if (isset($this->data[$val])) {
|
||||
$relation[$key][$val] = $this->data[$val];
|
||||
unset($this->data[$val]);
|
||||
if (is_array($name)) {
|
||||
if (key($name) === 0) {
|
||||
$relation[$key] = [];
|
||||
foreach ($name as $val) {
|
||||
if (isset($this->data[$val])) {
|
||||
$relation[$key][$val] = $this->data[$val];
|
||||
unset($this->data[$val]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$relation[$key] = $name;
|
||||
}
|
||||
} elseif (isset($this->relation[$name])) {
|
||||
$relation[$name] = $this->relation[$name];
|
||||
} elseif (isset($this->data[$name])) {
|
||||
$relation[$name] = $this->data[$name];
|
||||
if (!$this->isUpdate) {
|
||||
unset($this->data[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检测字段
|
||||
if (!empty($this->field)) {
|
||||
if (true === $this->field) {
|
||||
$this->field = $this->db(false)->getTableInfo('', 'fields');
|
||||
}
|
||||
foreach ($this->data as $key => $val) {
|
||||
if (!in_array($key, $this->field)) {
|
||||
unset($this->data[$key]);
|
||||
unset($this->data[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -845,33 +952,25 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
$pk = $this->getPk();
|
||||
if ($this->isUpdate) {
|
||||
// 检测字段
|
||||
$this->checkAllowField($this->data, array_merge($this->auto, $this->update));
|
||||
|
||||
// 自动更新
|
||||
$this->autoCompleteData($this->update);
|
||||
|
||||
// 获取有更新的数据
|
||||
$data = $this->getChangedData();
|
||||
|
||||
// 事件回调
|
||||
if (false === $this->trigger('before_update', $this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 去除没有更新的字段
|
||||
$data = [];
|
||||
foreach ($this->data as $key => $val) {
|
||||
if (in_array($key, $this->change) || $this->isPk($key)) {
|
||||
$data[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->readonly)) {
|
||||
// 只读字段不允许更新
|
||||
foreach ($this->readonly as $key => $field) {
|
||||
if (isset($data[$field])) {
|
||||
unset($data[$field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($data) || (count($data) == 1 && is_string($pk) && isset($data[$pk]))) {
|
||||
// 没有更新
|
||||
// 关联更新
|
||||
if (isset($relation)) {
|
||||
$this->autoRelationUpdate($relation);
|
||||
}
|
||||
return 0;
|
||||
} elseif ($this->autoWriteTimestamp && $this->updateTime && !isset($data[$this->updateTime])) {
|
||||
// 自动写入更新时间
|
||||
@@ -882,6 +981,13 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$where = $this->updateWhere;
|
||||
}
|
||||
|
||||
// 保留主键数据
|
||||
foreach ($this->data as $key => $val) {
|
||||
if ($this->isPk($key)) {
|
||||
$data[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_string($pk) && isset($data[$pk])) {
|
||||
if (!isset($where[$pk])) {
|
||||
unset($where);
|
||||
@@ -890,40 +996,24 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
unset($data[$pk]);
|
||||
}
|
||||
|
||||
// 关联更新
|
||||
if (isset($relation)) {
|
||||
foreach ($relation as $name => $val) {
|
||||
if (isset($data[$name])) {
|
||||
unset($data[$name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 模型更新
|
||||
$result = $this->db()->where($where)->update($data);
|
||||
$result = $this->getQuery()->where($where)->update($data);
|
||||
|
||||
// 关联更新
|
||||
if (isset($relation)) {
|
||||
foreach ($relation as $name => $val) {
|
||||
if ($val instanceof Model) {
|
||||
$val->save();
|
||||
} else {
|
||||
unset($this->data[$name]);
|
||||
$model = $this->getAttr($name);
|
||||
if ($model instanceof Model) {
|
||||
$model->save($val);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->autoRelationUpdate($relation);
|
||||
}
|
||||
|
||||
// 清空change
|
||||
$this->change = [];
|
||||
// 更新回调
|
||||
$this->trigger('after_update', $this);
|
||||
|
||||
} else {
|
||||
// 检测字段
|
||||
$this->checkAllowField($this->data, array_merge($this->auto, $this->insert));
|
||||
|
||||
// 自动写入
|
||||
$this->autoCompleteData($this->insert);
|
||||
|
||||
// 自动写入创建时间和更新时间
|
||||
if ($this->autoWriteTimestamp) {
|
||||
if ($this->createTime && !isset($this->data[$this->createTime])) {
|
||||
@@ -938,11 +1028,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $this->db()->insert($this->data);
|
||||
$result = $this->getQuery()->insert($this->data);
|
||||
|
||||
// 获取自动增长主键
|
||||
if ($result && is_string($pk) && (!isset($this->data[$pk]) || '' == $this->data[$pk])) {
|
||||
$insertId = $this->db()->getLastInsID($sequence);
|
||||
$insertId = $this->getQuery()->getLastInsID($sequence);
|
||||
if ($insertId) {
|
||||
$this->data[$pk] = $insertId;
|
||||
}
|
||||
@@ -958,17 +1048,78 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
|
||||
// 标记为更新
|
||||
$this->isUpdate = true;
|
||||
// 清空change
|
||||
$this->change = [];
|
||||
|
||||
// 新增回调
|
||||
$this->trigger('after_insert', $this);
|
||||
}
|
||||
// 写入回调
|
||||
$this->trigger('after_write', $this);
|
||||
|
||||
// 重新记录原始数据
|
||||
$this->origin = $this->data;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function checkAllowField(&$data, $auto = [])
|
||||
{
|
||||
if (!empty($this->field)) {
|
||||
if (true === $this->field) {
|
||||
$this->field = $this->getQuery()->getTableInfo('', 'fields');
|
||||
$field = $this->field;
|
||||
} else {
|
||||
$field = array_merge($this->field, $auto);
|
||||
}
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
if (!in_array($key, $field)) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function autoRelationUpdate($relation)
|
||||
{
|
||||
foreach ($relation as $name => $val) {
|
||||
if ($val instanceof Model) {
|
||||
$val->save();
|
||||
} else {
|
||||
unset($this->data[$name]);
|
||||
$model = $this->getAttr($name);
|
||||
if ($model instanceof Model) {
|
||||
$model->save($val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取变化的数据 并排除只读数据
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
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 (!empty($this->readonly)) {
|
||||
// 只读字段不允许更新
|
||||
foreach ($this->readonly as $key => $field) {
|
||||
if (isset($data[$field])) {
|
||||
unset($data[$field]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存多个数据到当前数据对象
|
||||
* @access public
|
||||
@@ -990,7 +1141,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$db = $this->db();
|
||||
$db = $this->getQuery();
|
||||
$db->startTrans();
|
||||
try {
|
||||
$pk = $this->getPk();
|
||||
@@ -1071,9 +1222,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$field = $value;
|
||||
$value = null;
|
||||
}
|
||||
if (!in_array($field, $this->change)) {
|
||||
$this->setAttr($field, !is_null($value) ? $value : (isset($this->data[$field]) ? $this->data[$field] : $value));
|
||||
|
||||
if (!isset($this->data[$field])) {
|
||||
$default = null;
|
||||
} else {
|
||||
$default = $this->data[$field];
|
||||
}
|
||||
|
||||
$this->setAttr($field, !is_null($value) ? $value : $default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1099,7 +1255,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
|
||||
// 删除当前模型数据
|
||||
$result = $this->db()->where($where)->delete();
|
||||
$result = $this->getQuery()->where($where)->delete();
|
||||
|
||||
// 关联删除
|
||||
if (!empty($this->relationWrite)) {
|
||||
@@ -1113,6 +1269,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
|
||||
$this->trigger('after_delete', $this);
|
||||
// 清空原始数据
|
||||
$this->origin = [];
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -1207,7 +1366,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
/**
|
||||
* 返回模型的错误信息
|
||||
* @access public
|
||||
* @return string
|
||||
* @return string|array
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
@@ -1294,11 +1453,15 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* @param mixed $data 主键值或者查询条件(闭包)
|
||||
* @param array|string $with 关联预查询
|
||||
* @param bool $cache 是否缓存
|
||||
* @return static
|
||||
* @return static|null
|
||||
* @throws exception\DbException
|
||||
*/
|
||||
public static function get($data = null, $with = [], $cache = false)
|
||||
public static function get($data, $with = [], $cache = false)
|
||||
{
|
||||
if (is_null($data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (true === $with || is_int($with)) {
|
||||
$cache = $with;
|
||||
$with = [];
|
||||
@@ -1366,7 +1529,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
} elseif ($data instanceof \Closure) {
|
||||
call_user_func_array($data, [ & $query]);
|
||||
$data = null;
|
||||
} elseif (is_null($data)) {
|
||||
} elseif (empty($data) && 0 !== $data) {
|
||||
return 0;
|
||||
}
|
||||
$resultSet = $query->select($data);
|
||||
@@ -1385,16 +1548,14 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
* @access public
|
||||
* @param string|array|\Closure $name 命名范围名称 逗号分隔
|
||||
* @internal mixed ...$params 参数调用
|
||||
* @return Model|Query
|
||||
* @return Query
|
||||
*/
|
||||
public static function scope($name)
|
||||
{
|
||||
if ($name instanceof Query) {
|
||||
return $name;
|
||||
}
|
||||
$model = new static();
|
||||
$params = func_get_args();
|
||||
$params[0] = $model->db();
|
||||
$model = new static();
|
||||
$query = $model->db();
|
||||
$params = func_get_args();
|
||||
array_unshift($params, $query);
|
||||
if ($name instanceof \Closure) {
|
||||
call_user_func_array($name, $params);
|
||||
} elseif (is_string($name)) {
|
||||
@@ -1408,7 +1569,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
}
|
||||
}
|
||||
return $model;
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1419,9 +1580,8 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public static function useGlobalScope($use)
|
||||
{
|
||||
$model = new static();
|
||||
static::$db = $model->db($use);
|
||||
return $model;
|
||||
$model = new static();
|
||||
return $model->db($use);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1638,7 +1798,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$model = $this->parseModel($model);
|
||||
$foreignKey = $foreignKey ?: $this->getForeignKey($model);
|
||||
$localKey = $localKey ?: (new $model)->getPk();
|
||||
return new BelongsTo($this, $model, $foreignKey, $localKey, $joinType);
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$relation = Loader::parseName($trace[1]['function']);
|
||||
return new BelongsTo($this, $model, $foreignKey, $localKey, $joinType, $relation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1693,7 +1855,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
// 记录当前关联信息
|
||||
$model = $this->parseModel($model);
|
||||
$name = Loader::parseName(basename(str_replace('\\', '/', $model)));
|
||||
$table = $table ?: $this->db(false)->getTable(Loader::parseName($this->name) . '_' . $name);
|
||||
$table = $table ?: $this->getQuery()->getTable(Loader::parseName($this->name) . '_' . $name);
|
||||
$foreignKey = $foreignKey ?: $name . '_id';
|
||||
$localKey = $localKey ?: $this->getForeignKey($this->name);
|
||||
return new BelongsToMany($this, $model, $table, $foreignKey, $localKey);
|
||||
@@ -1725,6 +1887,32 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
return new MorphMany($this, $model, $foreignKey, $morphType, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* MORPH One 关联定义
|
||||
* @access public
|
||||
* @param string $model 模型名
|
||||
* @param string|array $morph 多态字段信息
|
||||
* @param string $type 多态类型
|
||||
* @return MorphOne
|
||||
*/
|
||||
public function morphOne($model, $morph = null, $type = '')
|
||||
{
|
||||
// 记录当前关联信息
|
||||
$model = $this->parseModel($model);
|
||||
if (is_null($morph)) {
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$morph = Loader::parseName($trace[1]['function']);
|
||||
}
|
||||
$type = $type ?: Loader::parseName($this->name);
|
||||
if (is_array($morph)) {
|
||||
list($morphType, $foreignKey) = $morph;
|
||||
} else {
|
||||
$morphType = $morph . '_type';
|
||||
$foreignKey = $morph . '_id';
|
||||
}
|
||||
return new MorphOne($this, $model, $foreignKey, $morphType, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* MORPH TO 关联定义
|
||||
* @access public
|
||||
@@ -1734,9 +1922,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public function morphTo($morph = null, $alias = [])
|
||||
{
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$relation = Loader::parseName($trace[1]['function']);
|
||||
|
||||
if (is_null($morph)) {
|
||||
$trace = debug_backtrace(false, 2);
|
||||
$morph = Loader::parseName($trace[1]['function']);
|
||||
$morph = $relation;
|
||||
}
|
||||
// 记录当前关联信息
|
||||
if (is_array($morph)) {
|
||||
@@ -1745,17 +1935,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
$morphType = $morph . '_type';
|
||||
$foreignKey = $morph . '_id';
|
||||
}
|
||||
return new MorphTo($this, $morphType, $foreignKey, $alias);
|
||||
return new MorphTo($this, $morphType, $foreignKey, $alias, $relation);
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (isset(static::$db)) {
|
||||
$query = static::$db;
|
||||
static::$db = null;
|
||||
} else {
|
||||
$query = $this->db();
|
||||
}
|
||||
$query = $this->db(true, false);
|
||||
|
||||
if (method_exists($this, 'scope' . $method)) {
|
||||
// 动态调用命名范围
|
||||
@@ -1768,16 +1953,21 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
}
|
||||
}
|
||||
|
||||
public static function __callStatic($method, $params)
|
||||
public static function __callStatic($method, $args)
|
||||
{
|
||||
if (isset(static::$db)) {
|
||||
$query = static::$db;
|
||||
static::$db = null;
|
||||
} else {
|
||||
$query = (new static())->db();
|
||||
}
|
||||
$model = new static();
|
||||
$query = $model->db();
|
||||
|
||||
return call_user_func_array([$query, $method], $params);
|
||||
if (method_exists($model, 'scope' . $method)) {
|
||||
// 动态调用命名范围
|
||||
$method = 'scope' . $method;
|
||||
array_unshift($args, $query);
|
||||
|
||||
call_user_func_array([$model, $method], $args);
|
||||
return $query;
|
||||
} else {
|
||||
return call_user_func_array([$query, $method], $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1812,7 +2002,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
public function __isset($name)
|
||||
{
|
||||
try {
|
||||
if (array_key_exists($name, $this->data)) {
|
||||
if (array_key_exists($name, $this->data) || array_key_exists($name, $this->relation)) {
|
||||
return true;
|
||||
} else {
|
||||
$this->getAttr($name);
|
||||
@@ -1832,7 +2022,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess
|
||||
*/
|
||||
public function __unset($name)
|
||||
{
|
||||
unset($this->data[$name]);
|
||||
unset($this->data[$name], $this->relation[$name]);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
|
||||
Reference in New Issue
Block a user