From 3f7113558c03a9580b360f3fa3a91171c325ec33 Mon Sep 17 00:00:00 2001 From: thinkphp Date: Sun, 17 Apr 2016 22:34:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E5=A4=9A=E5=AF=B9=E5=A4=9A?= =?UTF-8?q?=E5=85=B3=E8=81=94=E6=9F=A5=E8=AF=A2=E5=8F=8A=E9=A2=84=E8=BD=BD?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/think/Model.php | 13 ++-- library/think/db/Query.php | 1 + library/think/model/Relation.php | 110 ++++++++++++++++++++++++++----- 3 files changed, 104 insertions(+), 20 deletions(-) diff --git a/library/think/Model.php b/library/think/Model.php index 853da7f9..a4519732 100644 --- a/library/think/Model.php +++ b/library/think/Model.php @@ -803,17 +803,20 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * BELONGS TO MANY 关联定义 * @access public * @param string $model 模型名 - * @param string $localKey 关联主键 - * @param string $foreignKey 关联外键 + * @param string $table 中间表名 + * @param string $localKey 当前模型关联键 + * @param string $foreignKey 关联模型关联键 * @return \think\db\Query|string */ - public function belongsToMany($model, $localKey = '', $foreignKey = '') + public function belongsToMany($model, $table = '', $localKey = '', $foreignKey = '') { // 记录当前关联信息 $model = $this->parseModel($model); - $foreignKey = $foreignKey ?: $this->pk; + $table = $table ?: Db::name(strtolower($this->name . '_' . basename(str_replace('\\', '/', $model))))->getTableName(); $localKey = $localKey ?: Loader::parseName(basename(str_replace('\\', '/', $model))) . '_id'; - return $this->relation->belongsToMany($model, $foreignKey, $localKey); + $foreignKey = $foreignKey ?: strtolower($this->name) . '_id'; + + return $this->relation->belongsToMany($model, $table, $localKey, $foreignKey); } /** diff --git a/library/think/db/Query.php b/library/think/db/Query.php index 80a491ca..02bbf543 100644 --- a/library/think/db/Query.php +++ b/library/think/db/Query.php @@ -362,6 +362,7 @@ class Query * @param boolean $except 是否排除 * @param string $tableName 数据表名 * @param string $prefix 字段前缀 + * @param string $alias 别名前缀 * @return $this */ public function field($field, $except = false, $tableName = '', $prefix = '', $alias = '') diff --git a/library/think/model/Relation.php b/library/think/model/Relation.php index b711b0c5..b8bca346 100644 --- a/library/think/model/Relation.php +++ b/library/think/model/Relation.php @@ -116,7 +116,6 @@ class Relation } break; case self::HAS_MANY: - case self::BELONGS_TO_MANY: $range = []; foreach ($resultSet as $result) { // 获取关联外键列表 @@ -126,7 +125,7 @@ class Relation } if (!empty($range)) { - $data = $this->eagerly($model, [$foreignKey => ['in', $range]], $relation, $subRelation); + $data = $this->eagerlyOneToMany($model, [$foreignKey => ['in', $range]], $relation, $subRelation); // 关联数据封装 foreach ($resultSet as $result) { @@ -138,6 +137,30 @@ class Relation } } break; + case self::BELONGS_TO_MANY: + $pk = $resultSet[0]->getPk(); + $range = []; + foreach ($resultSet as $result) { + // 获取关联外键列表 + if (isset($result->$pk)) { + $range[] = $result->$pk; + } + } + + if (!empty($range)) { + $condition[$this->middle . '.' . $foreignKey] = ['in', $range]; + $data = $this->eagerlyManyToMany($model, $condition, $relation, $subRelation); + + // 关联数据封装 + foreach ($resultSet as $result) { + if (isset($data[$result->$pk])) { + $result->__set($relation, $data[$result->$pk]); + } else { + $result->__set($relation, []); + } + } + } + break; } $this->relation = []; } @@ -173,9 +196,8 @@ class Relation $this->match($model, $relation, $result); break; case self::HAS_MANY: - case self::BELONGS_TO_MANY: if (isset($result->$localKey)) { - $data = $this->eagerly($model, [$foreignKey => $result->$localKey], $relation, $subRelation); + $data = $this->eagerlyOneToMany($model, [$foreignKey => $result->$localKey], $relation, $subRelation); // 关联数据封装 if (!isset($data[$result->$localKey])) { $data[$result->$localKey] = []; @@ -183,6 +205,19 @@ class Relation $result->__set($relation, $data[$result->$localKey]); } break; + case self::BELONGS_TO_MANY: + $pk = $result->getPk(); + $condition[$this->middle . '.' . $foreignKey] = $this->parent->$pk; + if (isset($result->$pk)) { + $data = $this->eagerlyManyToMany($model, $condition, $relation, $subRelation); + // 关联数据封装 + if (!isset($data[$result->$pk])) { + $data[$result->$pk] = []; + } + $result->__set($relation, $data[$result->$pk]); + } + break; + } } $this->eagerly = false; @@ -227,7 +262,7 @@ class Relation * @param string $subRelation 子关联 * @return void */ - protected function eagerly($model, $where, $relation, $subRelation = '') + protected function eagerlyOneToMany($model, $where, $relation, $subRelation = '') { $foreignKey = $this->foreignKey; // 预载入关联查询 支持嵌套预载入 @@ -241,6 +276,29 @@ class Relation return $data; } + /** + * 多对多 关联模型预查询 + * @access public + * @param string $model 模型名称 + * @param array $where 关联预查询条件 + * @param string $relation 关联名 + * @param string $subRelation 子关联 + * @return void + */ + protected function eagerlyManyToMany($model, $where, $relation, $subRelation = '') + { + $foreignKey = $this->foreignKey; + // 预载入关联查询 支持嵌套预载入 + $list = $this->belongsToManyQuery($model, $this->middle, $this->localKey, $this->foreignKey, $where)->with($subRelation)->select(); + + // 组装模型数据 + $data = []; + foreach ($list as $set) { + $data[$set->$foreignKey][] = $set; + } + return $data; + } + /** * HAS ONE 关联定义 * @access public @@ -249,7 +307,7 @@ class Relation * @param string $localKey 关联主键 * @return \think\db\Query|string */ - public function hasOne($model, $foreignKey = '', $localKey = '') + public function hasOne($model, $foreignKey, $localKey) { $this->type = self::HAS_ONE; $this->model = $model; @@ -273,7 +331,7 @@ class Relation * @param string $foreignKey 关联外键 * @return \think\db\Query|string */ - public function belongsTo($model, $localKey = '', $foreignKey = '') + public function belongsTo($model, $localKey, $foreignKey) { // 记录当前关联信息 $this->type = self::BELONGS_TO; @@ -298,7 +356,7 @@ class Relation * @param string $localKey 关联主键 * @return \think\db\Query|string */ - public function hasMany($model, $foreignKey = '', $localKey = '') + public function hasMany($model, $foreignKey, $localKey) { // 记录当前关联信息 $this->type = self::HAS_MANY; @@ -319,25 +377,47 @@ class Relation * BELONGS TO MANY 关联定义 * @access public * @param string $model 模型名 - * @param string $localKey 关联主键 - * @param string $foreignKey 关联外键 + * @param string $table 中间表名 + * @param string $localKey 当前模型关联键 + * @param string $foreignKey 关联模型关联键 * @return \think\db\Query|string */ - public function belongsToMany($model, $localKey = '', $foreignKey = '') + public function belongsToMany($model, $table, $localKey, $foreignKey) { // 记录当前关联信息 $this->type = self::BELONGS_TO_MANY; $this->model = $model; $this->foreignKey = $foreignKey; $this->localKey = $localKey; - - if (!$this->eagerly && isset($this->parent->$localKey)) { - // 关联查询封装 - return $model::where($foreignKey, $this->parent->$localKey); + $this->middle = $table; + $pk = $this->parent->getPk(); + if (!$this->eagerly && isset($this->parent->$pk)) { + // 关联查询 + $condition[$table . '.' . $foreignKey] = $this->parent->$pk; + return $this->belongsToManyQuery($model, $table, $localKey, $foreignKey, $condition); } else { // 预载入封装 return $model; } } + /** + * BELONGS TO MANY 关联查询 + * @access public + * @param string $model 模型名 + * @param string $table 中间表名 + * @param string $localKey 当前模型关联键 + * @param string $foreignKey 关联模型关联键 + * @param array $condition 关联查询条件 + * @return \think\db\Query|string + */ + protected function belongsToManyQuery($model, $table, $localKey, $foreignKey, $condition = []) + { + // 关联查询封装 + $tableName = $model::getTableName(); + $relationFk = (new $model)->getPk(); + return $model::join($table, $table . '.' . $localKey . '=' . $tableName . '.' . $relationFk) + ->where($condition); + } + }