MorphTo.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2017 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. namespace think\model\relation;
  12. use think\Exception;
  13. use think\Loader;
  14. use think\Model;
  15. use think\model\Relation;
  16. class MorphTo extends Relation
  17. {
  18. // 多态字段
  19. protected $morphKey;
  20. protected $morphType;
  21. // 多态别名
  22. protected $alias;
  23. /**
  24. * 架构函数
  25. * @access public
  26. * @param Model $parent 上级模型对象
  27. * @param string $morphType 多态字段名
  28. * @param string $morphKey 外键名
  29. * @param array $alias 多态别名定义
  30. */
  31. public function __construct(Model $parent, $morphType, $morphKey, $alias = [])
  32. {
  33. $this->parent = $parent;
  34. $this->morphType = $morphType;
  35. $this->morphKey = $morphKey;
  36. $this->alias = $alias;
  37. }
  38. /**
  39. * 延迟获取关联数据
  40. * @param string $subRelation 子关联名
  41. * @param \Closure $closure 闭包查询条件
  42. * @return mixed
  43. */
  44. public function getRelation($subRelation = '', $closure = null)
  45. {
  46. $morphKey = $this->morphKey;
  47. $morphType = $this->morphType;
  48. // 多态模型
  49. $model = $this->parseModel($this->parent->$morphType);
  50. // 主键数据
  51. $pk = $this->parent->$morphKey;
  52. return (new $model)->relation($subRelation)->find($pk);
  53. }
  54. /**
  55. * 解析模型的完整命名空间
  56. * @access public
  57. * @param string $model 模型名(或者完整类名)
  58. * @return string
  59. */
  60. protected function parseModel($model)
  61. {
  62. if (isset($this->alias[$model])) {
  63. $model = $this->alias[$model];
  64. }
  65. if (false === strpos($model, '\\')) {
  66. $path = explode('\\', get_class($this->parent));
  67. array_pop($path);
  68. array_push($path, Loader::parseName($model, 1));
  69. $model = implode('\\', $path);
  70. }
  71. return $model;
  72. }
  73. /**
  74. * 设置多态别名
  75. * @access public
  76. * @param array $alias 别名定义
  77. * @return $this
  78. */
  79. public function setAlias($alias)
  80. {
  81. $this->alias = $alias;
  82. return $this;
  83. }
  84. /**
  85. * 预载入关联查询
  86. * @access public
  87. * @param array $resultSet 数据集
  88. * @param string $relation 当前关联名
  89. * @param string $subRelation 子关联名
  90. * @param \Closure $closure 闭包
  91. * @return void
  92. * @throws Exception
  93. */
  94. public function eagerlyResultSet(&$resultSet, $relation, $subRelation, $closure)
  95. {
  96. $morphKey = $this->morphKey;
  97. $morphType = $this->morphType;
  98. $range = [];
  99. foreach ($resultSet as $result) {
  100. // 获取关联外键列表
  101. if (!empty($result->$morphKey)) {
  102. $range[$result->$morphType][] = $result->$morphKey;
  103. }
  104. }
  105. if (!empty($range)) {
  106. // 关联属性名
  107. $attr = Loader::parseName($relation);
  108. foreach ($range as $key => $val) {
  109. // 多态类型映射
  110. $model = $this->parseModel($key);
  111. $obj = new $model;
  112. $pk = $obj->getPk();
  113. $list = $obj->all($val, $subRelation);
  114. $data = [];
  115. foreach ($list as $k => $vo) {
  116. $data[$vo->$pk] = $vo;
  117. }
  118. foreach ($resultSet as $result) {
  119. if ($key == $result->$morphType) {
  120. // 关联模型
  121. if (!isset($data[$result->$morphKey])) {
  122. throw new Exception('relation data not exists :' . $this->model);
  123. } else {
  124. $result->setAttr($attr, $data[$result->$morphKey]);
  125. }
  126. }
  127. }
  128. }
  129. }
  130. }
  131. /**
  132. * 预载入关联查询
  133. * @access public
  134. * @param Model $result 数据对象
  135. * @param string $relation 当前关联名
  136. * @param string $subRelation 子关联名
  137. * @param \Closure $closure 闭包
  138. * @return void
  139. */
  140. public function eagerlyResult(&$result, $relation, $subRelation, $closure)
  141. {
  142. $morphKey = $this->morphKey;
  143. $morphType = $this->morphType;
  144. // 多态类型映射
  145. $model = $this->parseModel($result->{$this->morphType});
  146. $this->eagerlyMorphToOne($model, $relation, $result, $subRelation);
  147. }
  148. /**
  149. * 关联统计
  150. * @access public
  151. * @param Model $result 数据对象
  152. * @param \Closure $closure 闭包
  153. * @return integer
  154. */
  155. public function relationCount($result, $closure)
  156. {
  157. }
  158. /**
  159. * 多态MorphTo 关联模型预查询
  160. * @access public
  161. * @param object $model 关联模型对象
  162. * @param string $relation 关联名
  163. * @param $result
  164. * @param string $subRelation 子关联
  165. * @return void
  166. */
  167. protected function eagerlyMorphToOne($model, $relation, &$result, $subRelation = '')
  168. {
  169. // 预载入关联查询 支持嵌套预载入
  170. $pk = $this->parent->{$this->morphKey};
  171. $data = (new $model)->with($subRelation)->find($pk);
  172. if ($data) {
  173. $data->isUpdate(true);
  174. }
  175. $result->setAttr(Loader::parseName($relation), $data ?: null);
  176. }
  177. /**
  178. * 执行基础查询(进执行一次)
  179. * @access protected
  180. * @return void
  181. */
  182. protected function baseQuery()
  183. {
  184. }
  185. }