更新内核,API接口开发的一些尝试,后期会增加API接口开发这块
This commit is contained in:
@@ -16,6 +16,20 @@ use think\Model;
|
||||
|
||||
class Collection extends BaseCollection
|
||||
{
|
||||
/**
|
||||
* 返回数组中指定的一列
|
||||
* @param string $column_key
|
||||
* @param string|null $index_key
|
||||
* @return array
|
||||
*/
|
||||
public function column($column_key, $index_key = null)
|
||||
{
|
||||
if (function_exists('array_column')) {
|
||||
return array_column($this->toArray(), $column_key, $index_key);
|
||||
}
|
||||
return parent::column($column_key, $index_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟预载入关联查询
|
||||
* @access public
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace think\model;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Model;
|
||||
|
||||
@@ -120,22 +121,19 @@ class Merge extends Model
|
||||
* @access public
|
||||
* @param string $model 模型名称
|
||||
* @param array $data 数据
|
||||
* @param bool $insert 是否新增
|
||||
* @return array
|
||||
*/
|
||||
protected function parseData($model, $data, $insert = false)
|
||||
protected function parseData($model, $data)
|
||||
{
|
||||
$item = [];
|
||||
foreach ($data as $key => $val) {
|
||||
if ($insert || in_array($key, $this->change) || $this->isPk($key)) {
|
||||
if ($this->fk != $key && array_key_exists($key, $this->mapFields)) {
|
||||
list($name, $key) = explode('.', $this->mapFields[$key]);
|
||||
if ($model == $name) {
|
||||
$item[$key] = $val;
|
||||
}
|
||||
} else {
|
||||
if ($this->fk != $key && array_key_exists($key, $this->mapFields)) {
|
||||
list($name, $key) = explode('.', $this->mapFields[$key]);
|
||||
if ($model == $name) {
|
||||
$item[$key] = $val;
|
||||
}
|
||||
} else {
|
||||
$item[$key] = $val;
|
||||
}
|
||||
}
|
||||
return $item;
|
||||
@@ -174,6 +172,11 @@ class Merge extends Model
|
||||
$this->setAttr($this->updateTime, null);
|
||||
}
|
||||
|
||||
// 事件回调
|
||||
if (false === $this->trigger('before_write', $this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$db = $this->db();
|
||||
$db->startTrans();
|
||||
$pk = $this->getPk();
|
||||
@@ -190,8 +193,16 @@ class Merge extends Model
|
||||
$where = $this->updateWhere;
|
||||
}
|
||||
|
||||
// 获取有更新的数据
|
||||
$data = $this->getChangedData();
|
||||
// 保留主键数据
|
||||
foreach ($this->data as $key => $val) {
|
||||
if ($this->isPk($key)) {
|
||||
$data[$key] = $val;
|
||||
}
|
||||
}
|
||||
// 处理模型数据
|
||||
$data = $this->parseData($this->name, $this->data);
|
||||
$data = $this->parseData($this->name, $data);
|
||||
if (is_string($pk) && isset($data[$pk])) {
|
||||
if (!isset($where[$pk])) {
|
||||
unset($where);
|
||||
@@ -207,14 +218,12 @@ class Merge extends Model
|
||||
$name = is_int($key) ? $model : $key;
|
||||
$table = is_int($key) ? $db->getTable($model) : $model;
|
||||
// 处理关联模型数据
|
||||
$data = $this->parseData($name, $this->data);
|
||||
$query = new Query;
|
||||
if ($query->table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) {
|
||||
$data = $this->parseData($name, $data);
|
||||
if (Db::table($table)->strict(false)->where($this->fk, $this->data[$this->getPk()])->update($data)) {
|
||||
$result = 1;
|
||||
}
|
||||
}
|
||||
// 清空change
|
||||
$this->change = [];
|
||||
|
||||
// 新增回调
|
||||
$this->trigger('after_update', $this);
|
||||
} else {
|
||||
@@ -231,7 +240,7 @@ class Merge extends Model
|
||||
}
|
||||
|
||||
// 处理模型数据
|
||||
$data = $this->parseData($this->name, $this->data, true);
|
||||
$data = $this->parseData($this->name, $this->data);
|
||||
// 写入主表数据
|
||||
$result = $db->name($this->name)->strict(false)->insert($data);
|
||||
if ($result) {
|
||||
@@ -240,9 +249,6 @@ class Merge extends Model
|
||||
if ($insertId) {
|
||||
if (is_string($pk)) {
|
||||
$this->data[$pk] = $insertId;
|
||||
if ($this->fk == $pk) {
|
||||
$this->change[] = $pk;
|
||||
}
|
||||
}
|
||||
$this->data[$this->fk] = $insertId;
|
||||
}
|
||||
@@ -256,19 +262,20 @@ class Merge extends Model
|
||||
$name = is_int($key) ? $model : $key;
|
||||
$table = is_int($key) ? $db->getTable($model) : $model;
|
||||
// 处理关联模型数据
|
||||
$data = $this->parseData($name, $source, true);
|
||||
$query = new Query;
|
||||
$query->table($table)->strict(false)->insert($data);
|
||||
$data = $this->parseData($name, $source);
|
||||
Db::table($table)->strict(false)->insert($data);
|
||||
}
|
||||
}
|
||||
// 标记为更新
|
||||
$this->isUpdate = true;
|
||||
// 清空change
|
||||
$this->change = [];
|
||||
// 新增回调
|
||||
$this->trigger('after_insert', $this);
|
||||
}
|
||||
$db->commit();
|
||||
// 写入回调
|
||||
$this->trigger('after_write', $this);
|
||||
|
||||
$this->origin = $this->data;
|
||||
return $result;
|
||||
} catch (\Exception $e) {
|
||||
$db->rollback();
|
||||
|
||||
@@ -19,24 +19,26 @@ class Pivot extends Model
|
||||
/** @var Model */
|
||||
public $parent;
|
||||
|
||||
protected $autoWriteTimestamp = false;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* 架构函数
|
||||
* @access public
|
||||
* @param Model $parent
|
||||
* @param array|object $data 数据
|
||||
* @param string $table 中间数据表名
|
||||
* @param Model $parent 上级模型
|
||||
* @param array|object $data 数据
|
||||
* @param string $table 中间数据表名
|
||||
*/
|
||||
public function __construct(Model $parent, $data = [], $table = '')
|
||||
{
|
||||
if (is_object($data)) {
|
||||
$this->data = get_object_vars($data);
|
||||
} else {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
$this->parent = $parent;
|
||||
|
||||
$this->table = $table;
|
||||
if (is_null($this->name)) {
|
||||
$this->name = $table;
|
||||
}
|
||||
|
||||
parent::__construct($data);
|
||||
|
||||
$this->class = $this->name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@ abstract class Relation
|
||||
protected $foreignKey;
|
||||
// 关联表主键
|
||||
protected $localKey;
|
||||
// 关联查询参数
|
||||
protected $option;
|
||||
// 基础查询
|
||||
protected $baseQuery;
|
||||
|
||||
@@ -79,15 +77,30 @@ abstract class Relation
|
||||
return (new $this->model)->toCollection($resultSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除关联查询参数
|
||||
* @access public
|
||||
* @return $this
|
||||
*/
|
||||
public function removeOption()
|
||||
protected function getQueryFields($model)
|
||||
{
|
||||
$this->query->removeOption();
|
||||
return $this;
|
||||
$fields = $this->query->getOptions('field');
|
||||
return $this->getRelationQueryFields($fields, $model);
|
||||
}
|
||||
|
||||
protected function getRelationQueryFields($fields, $model)
|
||||
{
|
||||
if ($fields) {
|
||||
|
||||
if (is_string($fields)) {
|
||||
$fields = explode(',', $fields);
|
||||
}
|
||||
|
||||
foreach ($fields as &$field) {
|
||||
if (false === strpos($field, '.')) {
|
||||
$field = $model . '.' . $field;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$fields = $model . '.*';
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,10 +118,8 @@ abstract class Relation
|
||||
|
||||
$result = call_user_func_array([$this->query, $method], $args);
|
||||
if ($result instanceof Query) {
|
||||
$this->option = $result->getOptions();
|
||||
return $this;
|
||||
} else {
|
||||
$this->option = [];
|
||||
$this->baseQuery = false;
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,9 @@ class BelongsTo extends OneToOne
|
||||
* @param string $foreignKey 关联外键
|
||||
* @param string $localKey 关联主键
|
||||
* @param string $joinType JOIN类型
|
||||
* @param string $relation 关联名
|
||||
*/
|
||||
public function __construct(Model $parent, $model, $foreignKey, $localKey, $joinType = 'INNER')
|
||||
public function __construct(Model $parent, $model, $foreignKey, $localKey, $joinType = 'INNER', $relation = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->model = $model;
|
||||
@@ -33,6 +34,7 @@ class BelongsTo extends OneToOne
|
||||
$this->localKey = $localKey;
|
||||
$this->joinType = $joinType;
|
||||
$this->query = (new $model)->db();
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +50,16 @@ class BelongsTo extends OneToOne
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
return $this->query->where($this->localKey, $this->parent->$foreignKey)->relation($subRelation)->find();
|
||||
$relationModel = $this->query
|
||||
->where($this->localKey, $this->parent->$foreignKey)
|
||||
->relation($subRelation)
|
||||
->find();
|
||||
|
||||
if ($relationModel) {
|
||||
$relationModel->setParent(clone $this->parent);
|
||||
}
|
||||
|
||||
return $relationModel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,6 +139,8 @@ class BelongsTo extends OneToOne
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$foreignKey];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
|
||||
if ($relationModel && !empty($this->bindAttr)) {
|
||||
@@ -135,7 +148,7 @@ class BelongsTo extends OneToOne
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
// 设置关联属性
|
||||
$result->setAttr($attr, $relationModel);
|
||||
$result->setRelation($attr, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,13 +172,46 @@ class BelongsTo extends OneToOne
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$foreignKey];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
if ($relationModel && !empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
// 设置关联属性
|
||||
$result->setAttr(Loader::parseName($relation), $relationModel);
|
||||
$result->setRelation(Loader::parseName($relation), $relationModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加关联数据
|
||||
* @access public
|
||||
* @param Model $model 关联模型对象
|
||||
* @return Model
|
||||
*/
|
||||
public function associate($model)
|
||||
{
|
||||
$foreignKey = $this->foreignKey;
|
||||
$pk = $model->getPk();
|
||||
|
||||
$this->parent->setAttr($foreignKey, $model->$pk);
|
||||
$this->parent->save();
|
||||
|
||||
return $this->parent->setRelation($this->relation, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销关联数据
|
||||
* @access public
|
||||
* @return Model
|
||||
*/
|
||||
public function dissociate()
|
||||
{
|
||||
$foreignKey = $this->foreignKey;
|
||||
|
||||
$this->parent->setAttr($foreignKey, null);
|
||||
$this->parent->save();
|
||||
|
||||
return $this->parent->setRelation($this->relation, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,9 @@ class BelongsToMany extends Relation
|
||||
{
|
||||
// 中间表表名
|
||||
protected $middle;
|
||||
|
||||
// 中间表模型
|
||||
// 中间表模型名称
|
||||
protected $pivotName;
|
||||
// 中间表模型对象
|
||||
protected $pivot;
|
||||
|
||||
/**
|
||||
@@ -43,8 +44,14 @@ class BelongsToMany extends Relation
|
||||
$this->model = $model;
|
||||
$this->foreignKey = $foreignKey;
|
||||
$this->localKey = $localKey;
|
||||
$this->middle = $table;
|
||||
$this->query = (new $model)->db();
|
||||
if (false !== strpos($table, '\\')) {
|
||||
$this->pivotName = $table;
|
||||
$this->middle = basename(str_replace('\\', '/', $table));
|
||||
} else {
|
||||
$this->middle = $table;
|
||||
}
|
||||
$this->query = (new $model)->db();
|
||||
$this->pivot = $this->newPivot();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +61,7 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
public function pivot($pivot)
|
||||
{
|
||||
$this->pivot = $pivot;
|
||||
$this->pivotName = $pivot;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -63,9 +70,9 @@ class BelongsToMany extends Relation
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
protected function newPivot($data)
|
||||
protected function newPivot($data = [])
|
||||
{
|
||||
$pivot = $this->pivot ?: '\\think\\model\\Pivot';
|
||||
$pivot = $this->pivotName ?: '\\think\\model\\Pivot';
|
||||
return new $pivot($this->parent, $data, $this->middle);
|
||||
}
|
||||
|
||||
@@ -102,7 +109,7 @@ class BelongsToMany extends Relation
|
||||
// 关联查询
|
||||
$pk = $this->parent->getPk();
|
||||
$condition['pivot.' . $localKey] = $this->parent->$pk;
|
||||
return $this->belongsToManyQuery($middle, $foreignKey, $localKey, $condition);
|
||||
return $this->belongsToManyQuery($foreignKey, $localKey, $condition);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +121,7 @@ class BelongsToMany extends Relation
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [& $this->query]);
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
$result = $this->buildQuery()->relation($subRelation)->select();
|
||||
$this->hydratePivot($result);
|
||||
@@ -260,7 +267,7 @@ class BelongsToMany extends Relation
|
||||
$data[$result->$pk] = [];
|
||||
}
|
||||
|
||||
$result->setAttr($attr, $this->resultSetBuild($data[$result->$pk]));
|
||||
$result->setRelation($attr, $this->resultSetBuild($data[$result->$pk]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,7 +293,7 @@ class BelongsToMany extends Relation
|
||||
if (!isset($data[$pk])) {
|
||||
$data[$pk] = [];
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), $this->resultSetBuild($data[$pk]));
|
||||
$result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$pk]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +310,7 @@ class BelongsToMany extends Relation
|
||||
$count = 0;
|
||||
if (isset($result->$pk)) {
|
||||
$pk = $result->$pk;
|
||||
$count = $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, ['pivot.' . $this->localKey => $pk])->count();
|
||||
$count = $this->belongsToManyQuery($this->foreignKey, $this->localKey, ['pivot.' . $this->localKey => $pk])->count();
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
@@ -316,7 +323,7 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
public function getRelationCountQuery($closure)
|
||||
{
|
||||
return $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, [
|
||||
return $this->belongsToManyQuery($this->foreignKey, $this->localKey, [
|
||||
'pivot.' . $this->localKey => [
|
||||
'exp',
|
||||
'=' . $this->parent->getTable() . '.' . $this->parent->getPk(),
|
||||
@@ -335,7 +342,7 @@ class BelongsToMany extends Relation
|
||||
protected function eagerlyManyToMany($where, $relation, $subRelation = '')
|
||||
{
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
$list = $this->belongsToManyQuery($this->middle, $this->foreignKey, $this->localKey, $where)->with($subRelation)->select();
|
||||
$list = $this->belongsToManyQuery($this->foreignKey, $this->localKey, $where)->with($subRelation)->select();
|
||||
|
||||
// 组装模型数据
|
||||
$data = [];
|
||||
@@ -359,21 +366,23 @@ class BelongsToMany extends Relation
|
||||
/**
|
||||
* BELONGS TO MANY 关联查询
|
||||
* @access public
|
||||
* @param string $table 中间表名
|
||||
* @param string $foreignKey 关联模型关联键
|
||||
* @param string $localKey 当前模型关联键
|
||||
* @param array $condition 关联查询条件
|
||||
* @return Query
|
||||
*/
|
||||
protected function belongsToManyQuery($table, $foreignKey, $localKey, $condition = [])
|
||||
protected function belongsToManyQuery($foreignKey, $localKey, $condition = [])
|
||||
{
|
||||
// 关联查询封装
|
||||
$tableName = $this->query->getTable();
|
||||
$relationFk = $this->query->getPk();
|
||||
$query = $this->query->field($tableName . '.*')
|
||||
$tableName = $this->query->getTable();
|
||||
$table = $this->pivot->getTable();
|
||||
$fields = $this->getQueryFields($tableName);
|
||||
|
||||
$query = $this->query->field($fields)
|
||||
->field(true, false, $table, 'pivot', 'pivot__');
|
||||
|
||||
if (empty($this->baseQuery)) {
|
||||
$relationFk = $this->query->getPk();
|
||||
$query->join($table . ' pivot', 'pivot.' . $foreignKey . '=' . $tableName . '.' . $relationFk)
|
||||
->where($condition);
|
||||
}
|
||||
@@ -450,7 +459,7 @@ class BelongsToMany extends Relation
|
||||
$ids = (array) $id;
|
||||
foreach ($ids as $id) {
|
||||
$pivot[$this->foreignKey] = $id;
|
||||
$this->query->table($this->middle)->insert($pivot, true);
|
||||
$this->pivot->insert($pivot, true);
|
||||
$result[] = $this->newPivot($pivot);
|
||||
}
|
||||
if (count($result) == 1) {
|
||||
@@ -488,8 +497,7 @@ class BelongsToMany extends Relation
|
||||
if (isset($id)) {
|
||||
$pivot[$this->foreignKey] = is_array($id) ? ['in', $id] : $id;
|
||||
}
|
||||
$this->query->table($this->middle)->where($pivot)->delete();
|
||||
|
||||
$this->pivot->where($pivot)->delete();
|
||||
// 删除关联表数据
|
||||
if (isset($id) && $relationDel) {
|
||||
$model = $this->model;
|
||||
@@ -497,6 +505,55 @@ class BelongsToMany extends Relation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据同步
|
||||
* @param array $ids
|
||||
* @param bool $detaching
|
||||
* @return array
|
||||
*/
|
||||
public function sync($ids, $detaching = true)
|
||||
{
|
||||
$changes = [
|
||||
'attached' => [],
|
||||
'detached' => [],
|
||||
'updated' => [],
|
||||
];
|
||||
$pk = $this->parent->getPk();
|
||||
$current = $this->pivot->where($this->localKey, $this->parent->$pk)
|
||||
->column($this->foreignKey);
|
||||
$records = [];
|
||||
|
||||
foreach ($ids as $key => $value) {
|
||||
if (!is_array($value)) {
|
||||
$records[$value] = [];
|
||||
} else {
|
||||
$records[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$detach = array_diff($current, array_keys($records));
|
||||
|
||||
if ($detaching && count($detach) > 0) {
|
||||
$this->detach($detach);
|
||||
|
||||
$changes['detached'] = $detach;
|
||||
}
|
||||
|
||||
foreach ($records as $id => $attributes) {
|
||||
if (!in_array($id, $current)) {
|
||||
$this->attach($id, $attributes);
|
||||
$changes['attached'][] = $id;
|
||||
} elseif (count($attributes) > 0 &&
|
||||
$this->attach($id, $attributes)
|
||||
) {
|
||||
$changes['updated'][] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
return $changes;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行基础查询(进执行一次)
|
||||
* @access protected
|
||||
@@ -504,9 +561,10 @@ class BelongsToMany extends Relation
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery)) {
|
||||
$pk = $this->parent->getPk();
|
||||
$this->query->join($this->middle . ' pivot', 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk())->where('pivot.' . $this->localKey, $this->parent->$pk);
|
||||
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||
$pk = $this->parent->getPk();
|
||||
$table = $this->pivot->getTable();
|
||||
$this->query->join($table . ' pivot', 'pivot.' . $this->foreignKey . '=' . $this->query->getTable() . '.' . $this->query->getPk())->where('pivot.' . $this->localKey, $this->parent->$pk);
|
||||
$this->baseQuery = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
@@ -47,7 +46,14 @@ class HasMany extends Relation
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
return $this->relation($subRelation)->select();
|
||||
$list = $this->relation($subRelation)->select();
|
||||
$parent = clone $this->parent;
|
||||
|
||||
foreach ($list as &$model) {
|
||||
$model->setParent($parent);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +90,12 @@ class HasMany extends Relation
|
||||
if (!isset($data[$result->$localKey])) {
|
||||
$data[$result->$localKey] = [];
|
||||
}
|
||||
$result->setAttr($attr, $this->resultSetBuild($data[$result->$localKey]));
|
||||
|
||||
foreach ($data[$result->$localKey] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
}
|
||||
|
||||
$result->setRelation($attr, $this->resultSetBuild($data[$result->$localKey]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +119,12 @@ class HasMany extends Relation
|
||||
if (!isset($data[$result->$localKey])) {
|
||||
$data[$result->$localKey] = [];
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), $this->resultSetBuild($data[$result->$localKey]));
|
||||
|
||||
foreach ($data[$result->$localKey] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
}
|
||||
|
||||
$result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$result->$localKey]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
@@ -57,6 +56,7 @@ class HasManyThrough extends Relation
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
|
||||
return $this->relation($subRelation)->select();
|
||||
}
|
||||
|
||||
@@ -96,8 +96,7 @@ class HasManyThrough extends Relation
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* 预载入关联查询 返回模型对象
|
||||
@@ -110,8 +109,7 @@ class HasManyThrough extends Relation
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure, $class)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* 关联统计
|
||||
@@ -121,8 +119,7 @@ class HasManyThrough extends Relation
|
||||
* @return integer
|
||||
*/
|
||||
public function relationCount($result, $closure)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* 执行基础查询(进执行一次)
|
||||
@@ -131,12 +128,11 @@ class HasManyThrough extends Relation
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery)) {
|
||||
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||
$through = $this->through;
|
||||
$model = $this->model;
|
||||
$alias = Loader::parseName(basename(str_replace('\\', '/', $model)));
|
||||
$alias = Loader::parseName(basename(str_replace('\\', '/', $this->model)));
|
||||
$throughTable = $through::getTable();
|
||||
$pk = (new $this->model)->getPk();
|
||||
$pk = (new $through)->getPk();
|
||||
$throughKey = $this->throughKey;
|
||||
$modelTable = $this->parent->getTable();
|
||||
$this->query->field($alias . '.*')->alias($alias)
|
||||
|
||||
@@ -50,7 +50,13 @@ class HasOne extends OneToOne
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
// 判断关联类型执行查询
|
||||
return $this->query->where($this->foreignKey, $this->parent->$localKey)->relation($subRelation)->find();
|
||||
$relationModel = $this->query->where($this->foreignKey, $this->parent->$localKey)->relation($subRelation)->find();
|
||||
|
||||
if ($relationModel) {
|
||||
$relationModel->setParent(clone $this->parent);
|
||||
}
|
||||
|
||||
return $relationModel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,13 +138,15 @@ class HasOne extends OneToOne
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$localKey];
|
||||
}
|
||||
if ($relationModel && !empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
if (!empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
}
|
||||
// 设置关联属性
|
||||
$result->setAttr($attr, $relationModel);
|
||||
$result->setRelation($attr, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,13 +171,15 @@ class HasOne extends OneToOne
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$localKey];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
if (!empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
}
|
||||
|
||||
if ($relationModel && !empty($this->bindAttr)) {
|
||||
// 绑定关联属性
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), $relationModel);
|
||||
$result->setRelation(Loader::parseName($relation), $relationModel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\Db;
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
@@ -56,7 +55,14 @@ class MorphMany extends Relation
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
return $this->relation($subRelation)->select();
|
||||
$list = $this->relation($subRelation)->select();
|
||||
$parent = clone $this->parent;
|
||||
|
||||
foreach ($list as &$model) {
|
||||
$model->setParent($parent);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +125,11 @@ class MorphMany extends Relation
|
||||
if (!isset($data[$result->$pk])) {
|
||||
$data[$result->$pk] = [];
|
||||
}
|
||||
$result->setAttr($attr, $this->resultSetBuild($data[$result->$pk]));
|
||||
foreach ($data[$result->$pk] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
$result->setRelation($attr, $this->resultSetBuild($data[$result->$pk]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,7 +151,17 @@ class MorphMany extends Relation
|
||||
$this->morphKey => $result->$pk,
|
||||
$this->morphType => $this->type,
|
||||
], $relation, $subRelation, $closure);
|
||||
$result->setAttr(Loader::parseName($relation), $this->resultSetBuild($data[$result->$pk]));
|
||||
|
||||
if (!isset($data[$result->$pk])) {
|
||||
$data[$result->$pk] = [];
|
||||
}
|
||||
|
||||
foreach ($data[$result->$pk] as &$relationModel) {
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
|
||||
$result->setRelation(Loader::parseName($relation), $this->resultSetBuild($data[$result->$pk]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +273,7 @@ class MorphMany extends Relation
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery)) {
|
||||
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||
$pk = $this->parent->getPk();
|
||||
$map[$this->morphKey] = $this->parent->$pk;
|
||||
$map[$this->morphType] = $this->type;
|
||||
|
||||
229
core/library/think/model/relation/MorphOne.php
Normal file
229
core/library/think/model/relation/MorphOne.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\model\relation;
|
||||
|
||||
use think\db\Query;
|
||||
use think\Exception;
|
||||
use think\Loader;
|
||||
use think\Model;
|
||||
use think\model\Relation;
|
||||
|
||||
class MorphOne extends Relation
|
||||
{
|
||||
// 多态字段
|
||||
protected $morphKey;
|
||||
protected $morphType;
|
||||
// 多态类型
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @access public
|
||||
* @param Model $parent 上级模型对象
|
||||
* @param string $model 模型名
|
||||
* @param string $morphKey 关联外键
|
||||
* @param string $morphType 多态字段名
|
||||
* @param string $type 多态类型
|
||||
*/
|
||||
public function __construct(Model $parent, $model, $morphKey, $morphType, $type)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->model = $model;
|
||||
$this->type = $type;
|
||||
$this->morphKey = $morphKey;
|
||||
$this->morphType = $morphType;
|
||||
$this->query = (new $model)->db();
|
||||
}
|
||||
|
||||
/**
|
||||
* 延迟获取关联数据
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包查询条件
|
||||
* @return false|\PDOStatement|string|\think\Collection
|
||||
*/
|
||||
public function getRelation($subRelation = '', $closure = null)
|
||||
{
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this->query]);
|
||||
}
|
||||
$relationModel = $this->relation($subRelation)->find();
|
||||
|
||||
if ($relationModel) {
|
||||
$relationModel->setParent(clone $this->parent);
|
||||
}
|
||||
|
||||
return $relationModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据关联条件查询当前模型
|
||||
* @access public
|
||||
* @param string $operator 比较操作符
|
||||
* @param integer $count 个数
|
||||
* @param string $id 关联表的统计字段
|
||||
* @param string $joinType JOIN类型
|
||||
* @return Query
|
||||
*/
|
||||
public function has($operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据关联条件查询当前模型
|
||||
* @access public
|
||||
* @param mixed $where 查询条件(数组或者闭包)
|
||||
* @return Query
|
||||
*/
|
||||
public function hasWhere($where = [])
|
||||
{
|
||||
throw new Exception('relation not support: hasWhere');
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询
|
||||
* @access public
|
||||
* @param array $resultSet 数据集
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)
|
||||
{
|
||||
$morphType = $this->morphType;
|
||||
$morphKey = $this->morphKey;
|
||||
$type = $this->type;
|
||||
$range = [];
|
||||
foreach ($resultSet as $result) {
|
||||
$pk = $result->getPk();
|
||||
// 获取关联外键列表
|
||||
if (isset($result->$pk)) {
|
||||
$range[] = $result->$pk;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($range)) {
|
||||
$data = $this->eagerlyMorphToOne([
|
||||
$morphKey => ['in', $range],
|
||||
$morphType => $type,
|
||||
], $relation, $subRelation, $closure);
|
||||
// 关联属性名
|
||||
$attr = Loader::parseName($relation);
|
||||
// 关联数据封装
|
||||
foreach ($resultSet as $result) {
|
||||
if (!isset($data[$result->$pk])) {
|
||||
$relationModel = null;
|
||||
} else {
|
||||
$relationModel = $data[$result->$pk];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
}
|
||||
|
||||
$result->setRelation($attr, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预载入关联查询
|
||||
* @access public
|
||||
* @param Model $result 数据对象
|
||||
* @param string $relation 当前关联名
|
||||
* @param string $subRelation 子关联名
|
||||
* @param \Closure $closure 闭包
|
||||
* @return void
|
||||
*/
|
||||
public function eagerlyResult(&$result, $relation, $subRelation, $closure)
|
||||
{
|
||||
$pk = $result->getPk();
|
||||
if (isset($result->$pk)) {
|
||||
$pk = $result->$pk;
|
||||
$data = $this->eagerlyMorphToOne([
|
||||
$this->morphKey => $pk,
|
||||
$this->morphType => $this->type,
|
||||
], $relation, $subRelation, $closure);
|
||||
|
||||
if (isset($data[$pk])) {
|
||||
$relationModel = $data[$pk];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
} else {
|
||||
$relationModel = null;
|
||||
}
|
||||
|
||||
$result->setRelation(Loader::parseName($relation), $relationModel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 多态一对一 关联模型预查询
|
||||
* @access public
|
||||
* @param array $where 关联预查询条件
|
||||
* @param string $relation 关联名
|
||||
* @param string $subRelation 子关联
|
||||
* @param bool|\Closure $closure 闭包
|
||||
* @return array
|
||||
*/
|
||||
protected function eagerlyMorphToOne($where, $relation, $subRelation = '', $closure = false)
|
||||
{
|
||||
// 预载入关联查询 支持嵌套预载入
|
||||
if ($closure) {
|
||||
call_user_func_array($closure, [ & $this]);
|
||||
}
|
||||
$list = $this->query->where($where)->with($subRelation)->find();
|
||||
$morphKey = $this->morphKey;
|
||||
// 组装模型数据
|
||||
$data = [];
|
||||
foreach ($list as $set) {
|
||||
$data[$set->$morphKey][] = $set;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存(新增)当前关联数据对象
|
||||
* @access public
|
||||
* @param mixed $data 数据 可以使用数组 关联模型对象 和 关联对象的主键
|
||||
* @return Model|false
|
||||
*/
|
||||
public function save($data)
|
||||
{
|
||||
if ($data instanceof Model) {
|
||||
$data = $data->getData();
|
||||
}
|
||||
// 保存关联表数据
|
||||
$pk = $this->parent->getPk();
|
||||
|
||||
$model = new $this->model;
|
||||
$data[$this->morphKey] = $this->parent->$pk;
|
||||
$data[$this->morphType] = $this->type;
|
||||
return $model->save($data) ? $model : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行基础查询(进执行一次)
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
if (empty($this->baseQuery) && $this->parent->getData()) {
|
||||
$pk = $this->parent->getPk();
|
||||
$map[$this->morphKey] = $this->parent->$pk;
|
||||
$map[$this->morphType] = $this->type;
|
||||
$this->query->where($map);
|
||||
$this->baseQuery = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,7 @@ class MorphTo extends Relation
|
||||
protected $morphType;
|
||||
// 多态别名
|
||||
protected $alias;
|
||||
protected $relation;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
@@ -31,13 +32,15 @@ class MorphTo extends Relation
|
||||
* @param string $morphType 多态字段名
|
||||
* @param string $morphKey 外键名
|
||||
* @param array $alias 多态别名定义
|
||||
* @param string $relation 关联名
|
||||
*/
|
||||
public function __construct(Model $parent, $morphType, $morphKey, $alias = [])
|
||||
public function __construct(Model $parent, $morphType, $morphKey, $alias = [], $relation = null)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
$this->morphType = $morphType;
|
||||
$this->morphKey = $morphKey;
|
||||
$this->alias = $alias;
|
||||
$this->relation = $relation;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,8 +56,13 @@ class MorphTo extends Relation
|
||||
// 多态模型
|
||||
$model = $this->parseModel($this->parent->$morphType);
|
||||
// 主键数据
|
||||
$pk = $this->parent->$morphKey;
|
||||
return (new $model)->relation($subRelation)->find($pk);
|
||||
$pk = $this->parent->$morphKey;
|
||||
$relationModel = (new $model)->relation($subRelation)->find($pk);
|
||||
|
||||
if ($relationModel) {
|
||||
$relationModel->setParent(clone $this->parent);
|
||||
}
|
||||
return $relationModel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,7 +173,11 @@ class MorphTo extends Relation
|
||||
if (!isset($data[$result->$morphKey])) {
|
||||
throw new Exception('relation data not exists :' . $this->model);
|
||||
} else {
|
||||
$result->setAttr($attr, $data[$result->$morphKey]);
|
||||
$relationModel = $data[$result->$morphKey];
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
|
||||
$result->setRelation($attr, $relationModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,9 +229,46 @@ class MorphTo extends Relation
|
||||
$pk = $this->parent->{$this->morphKey};
|
||||
$data = (new $model)->with($subRelation)->find($pk);
|
||||
if ($data) {
|
||||
$data->setParent(clone $result);
|
||||
$data->isUpdate(true);
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), $data ?: null);
|
||||
$result->setRelation(Loader::parseName($relation), $data ?: null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加关联数据
|
||||
* @access public
|
||||
* @param Model $model 关联模型对象
|
||||
* @return Model
|
||||
*/
|
||||
public function associate($model)
|
||||
{
|
||||
$morphKey = $this->morphKey;
|
||||
$morphType = $this->morphType;
|
||||
$pk = $model->getPk();
|
||||
|
||||
$this->parent->setAttr($morphKey, $model->$pk);
|
||||
$this->parent->setAttr($morphType, get_class($model));
|
||||
$this->parent->save();
|
||||
|
||||
return $this->parent->setRelation($this->relation, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销关联数据
|
||||
* @access public
|
||||
* @return Model
|
||||
*/
|
||||
public function dissociate()
|
||||
{
|
||||
$morphKey = $this->morphKey;
|
||||
$morphType = $this->morphType;
|
||||
|
||||
$this->parent->setAttr($morphKey, null);
|
||||
$this->parent->setAttr($morphType, null);
|
||||
$this->parent->save();
|
||||
|
||||
return $this->parent->setRelation($this->relation, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,6 +277,5 @@ class MorphTo extends Relation
|
||||
* @return void
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ abstract class OneToOne extends Relation
|
||||
protected $joinType;
|
||||
// 要绑定的属性
|
||||
protected $bindAttr = [];
|
||||
// 关联方法名
|
||||
protected $relation;
|
||||
|
||||
/**
|
||||
* 设置join类型
|
||||
@@ -243,13 +245,19 @@ abstract class OneToOne extends Relation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($list[$relation])) {
|
||||
$relationModel = new $model($list[$relation]);
|
||||
$relationModel->setParent(clone $result);
|
||||
$relationModel->isUpdate(true);
|
||||
|
||||
if (!empty($this->bindAttr)) {
|
||||
$this->bindAttr($relationModel, $result, $this->bindAttr);
|
||||
}
|
||||
} else {
|
||||
$relationModel = null;
|
||||
}
|
||||
$result->setAttr(Loader::parseName($relation), !isset($relationModel) ? null : $relationModel->isUpdate(true));
|
||||
$result->setRelation(Loader::parseName($relation), $relationModel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,6 +317,5 @@ abstract class OneToOne extends Relation
|
||||
* @return void
|
||||
*/
|
||||
protected function baseQuery()
|
||||
{
|
||||
}
|
||||
{}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user