我一直在努力解决这个问题,无法真正找到解决方案,所以我希望得到一些帮助。
我有两个相关模型ModelOne
,它们也与自身相关,可以拥有无数个孩子,孙子等,并与ModelTwo
相关。
class ModelOne extends Model
{
...
public function model_two()
{
return $this->hasMany(ModelTwo::class, 'foreign_key');
}
//recursively get all children, grandchildren etc.
public function children() {
return $this->hasMany(ModelOne::class, 'foreign_key')->with('children');
}
public function parent() {
return $this->belongsTo(ModelOne::class, 'foreign_key');
}
}
class ModelTwo extends Model
{
...
public function model_one()
{
return $this->belongsTo(ModelOne::class, 'foreign_key');
}
}
在我ModelOne
的get函数中,我有:
public function get($id = null) {
return is_null($id) ?
ModelOne::withCount('model_two')->get() :
ModelOne::withCount('model_two')->where('id', $id)->first();
}
这给了我一个很好的一维对象数组(或一个对象),我需要的是与计数形式相关的ModelTwo
,但每个相关对象的个别计数。
我需要的是,对于返回数组中每个具有子项,孙子项等的ModelOne
个对象,要计算该对象中所有子项,孙子项等的计数总和。
因此,例如,如果我有一个ModelOne
的对象,其id = 2,parent_id = 1且计数为3,另一个对象的id = 3,parent_id = 1且计数为2,那么对于具有id的对象= 1,即前两个的父级,count将为5.此逻辑在树中继续为所有节点。
[
{
"id":1
"parent_id":"NULL",
"model_two_count":5
},
{
"id":2
"parent_id":1,
"model_two_count":3
},
{
"id":3
"parent_id":1,
"model_two_count":2
}
...
]
答案 0 :(得分:2)
所以,我想出了解决方案,这里适合所有可能遇到同样问题的人。
首先,在我的ModelOne
我添加了withCount('model_two')
,以便我立即从ModelTwo
获得关系计数。我还添加了一个属性$return_count
,它将保存所有子孙的计数总和等。
class ModelOne extends Model
{
private $return_count = 0;
...
public function model_two()
{
return $this->hasMany(ModelTwo::class, 'foreign_key');
}
//recursively get all children, grandchildren etc.
public function children() {
return $this->hasMany(ModelOne::class, 'foreign_key')->withCount('model_two')->with('children');
}
public function parent() {
return $this->belongsTo(ModelOne::class, 'foreign_key');
}
}
然后,我添加了两个辅助函数,一个递归地获取所有子孙 - 等等。对于给定的父ID,或者从表中返回所有记录:
public function get_recursive($parentId = null){
return is_null($parentId) ?
ModelOne::with('children')->get() :
ModelOne::where('id', $parentId)->with('children')->first();
}
此功能的输出如下:
[
{
"id":1
"parent_id":"NULL",
"model_two_count":0.
"children": [
{
"id":2
"parent_id":1,
"model_two_count":3
},
{
"id":3
"parent_id":1,
"model_two_count":2
}
]
}
...
]
此示例适用于二维嵌套,但它可以无限深。
在此函数中创建的返回对象成为第二个函数中的输入参数。第二个功能实际上是对所有子孙等的计数进行递归求和。对于给定的父对象。可以访问属性model_two_count
,因为它是在调用withCount('model_two')
时创建的。此外,在调用children
时会创建属性with('children')
。
private function count_sum($parentChildren) {
foreach ($parentChildren->children as $child) {
$this->return_count += $child->model_two_count;
$this->count_sum($child);
}
return $this->return_count;
}
最后我调用了我的get函数:
public function get($id = null) {
if(is_null($id = null)) {
$data = ModelOne::withCount('model_two')->get();
return $data->map(function ($i) {
//get all children-grandchildren-etc. for specfic object with id = $i->id
$children = $this->get_recursive($i->id);
//if object with id = $i->id have children then model_two_count is sum of all model_two_count from all children-grandchildren-etc.
if (!empty(array_filter((array)$children->children))) {
$i->model_two_count = $this->count_sum($children);
//reset the return_count variable for next iteration. If this is not done, then sum from previous object will be added to the next object count
$this->return_count = 0;
}
return $i;
});
} else {
$data = ModelOne::withCount('model_two')->where('id', $id)->get();
return $data->map(function ($i) {
$children = $this->get_recursive($i->id);
if (!empty(array_filter((array)$children->children))) {
$i->model_two_count = $this->count_sum($children);
$this->return_count = 0;
}
return $i;
})->first();
}
}
这样可以获得理想的输出效果:
[
{
"id":1
"parent_id":"NULL",
"model_two_count":5
},
{
"id":2
"parent_id":1,
"model_two_count":3
},
{
"id":3
"parent_id":1,
"model_two_count":2
}
...
]