问题描述
tp6 的远程一对一关联查询 当要查询的关联数据查询时会出现相同不是为null 的情况。
可能这个用的人比较少的原因,网上对hasOneThrough的相关资料比较少,出现这个问题就记录一下。
原因分析
下面是hasOneThrough的源码
```php public function hasOneThrough(string $model, string $through, string $foreignKey = '', string $throughKey = '', string $localKey = '', string $throughPk = ''): HasOneThrough { // 记录当前关联信息 $model = $this->parseModel($model); $through = $this->parseModel($through); $localKey = $localKey ?: $this->getPk(); $foreignKey = $foreignKey ?: $this->getForeignKey($this->name); $throughKey = $throughKey ?: $this->getForeignKey((new $through)->getName()); $throughPk = $throughPk ?: (new $through)->getPk(); return new HasOneThrough($this, $model, $through, $foreignKey, $throughKey, $localKey, $throughPk); }
我这里用的是VsCode,按住点击Crtrl 和 鼠标点击"HasOneThrough"
出现下面,选择右边下面远程一对一的双击,跳转到文件源码"HasOneThrough.php"
也可以直接找这文件,这 HasOneThrough.php 文件的路径为
vendor\topthink\think-orm\src\model\relation\HasOneThrough.php
找到 eagerlyWhere 方法,大概140行,基本是最后那个方法
protected function eagerlyWhere(array $where, string $key, array $subRelation = [], Closure $closure = null, array $cache = []): array { // 预载入关联查询 支持嵌套预载入 $keys = $this->through->where($where)->column($this->throughPk, $this->foreignKey); if ($closure) { $closure($this->getClosureType($closure)); } $list = $this->query ->where($this->throughKey, 'in', $keys) ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) ->select(); // 组装模型数据 $data = []; $keys = array_flip($keys); foreach ($list as $set) { $data[$keys[$set->{$this->throughKey}]] = $set; } return $data; }
相信细心的已经看到出问题的地方了,
正是这个array_flip()函数,这个函数的作用是:反转数组中的键名和对应关联的键值
举个简单的例子
原数组:Array ( [1] => 32 [2] => 32 )
array_flip()函数转换后
转换后: Array ( [32] => 2 )
这就是为什么相同的会部分显示为null 的原因了
解决方法
先贴修改后的代码
protected function eagerlyWhere(array $where, string $key, array $subRelation = [], Closure $closure = null, array $cache = []): array { // 预载入关联查询 支持嵌套预载入 $keys = $this->through->where($where)->column($this->throughPk, $this->foreignKey); if ($closure) { $closure($this->getClosureType($closure)); } $list = $this->query ->where($this->throughKey, 'in', $keys) ->cache($cache[0] ?? false, $cache[1] ?? null, $cache[2] ?? null) ->select(); // 组装模型数据 $data = []; // start 原代码 // $keys = array_flip($keys); // foreach ($list as $set) { // $data[$keys[$set->{$this->throughKey}]] = $set; // } // end // start 修改部分 $arr = []; foreach ($keys as $k => $v) { if (isset($arr[$v])) { array_push($arr[$v], $k); } else { $arr[$v][] = $k; } } foreach ($list as $set) { if (is_array($arr[$set->{$this->throughKey}])) { foreach ($arr[$set->{$this->throughKey}] as $key) { $data[$key] = $set; } } } // end return $data; }
修改后: Array ( [32] => Array ( [0] => 1 [1] => 2 ) )
也就是简单的将一维数组,转化为二维数组,之后就可以正常使用了。
这个方法可能还有可以优化的地方,有的话评论告知,相互学习。
来源地址:https://blog.csdn.net/zcc_520/article/details/127202821