Php Laravel-获取树结构中的计数,其中父级中的计数是来自子级的计数之和
我在这个问题上挣扎了一段时间,找不到解决办法,所以我希望能帮上忙 我有两个相关的模型,Php Laravel-获取树结构中的计数,其中父级中的计数是来自子级的计数之和,php,laravel,count,tree,relationships,Php,Laravel,Count,Tree,Relationships,我在这个问题上挣扎了一段时间,找不到解决办法,所以我希望能帮上忙 我有两个相关的模型,ModelOne,它也与自身相关,可以有无限多的子代、孙辈等,并且与ModelTwo相关 class ModelOne extends Model { ... public function model_two() { return $this->hasMany(ModelTwo::class, 'foreign_key'); } //recur
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
获取函数中,我有:
public function get($id = null) {
return is_null($id) ?
ModelOne::withCount('model_two')->get() :
ModelOne::withCount('model_two')->where('id', $id)->first();
}
这给了我一个很好的一维对象数组(或一个对象),带有计数形式相关的ModelTwo
,这是我需要的,但是每个相关对象都有单独的计数
我需要的是,对于返回数组中具有子对象、孙子对象等的每个ModelOne
对象,在该对象中计数是其所有子对象、孙子对象等的计数之和。
例如,如果我有一个id=2的ModelOne
对象,父对象id=1,计数为3,另一个对象id=3,父对象id=1,计数为2,那么对于id=1的对象,即前两个对象的父对象,计数为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
}
...
]
[
{
"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
}
...
]
所以,我找到了解决办法,这是给你们所有可能在同一个问题上挣扎的人的 首先,在我的
ModelOne
中,我添加了withCount('model_two')
,这样我可以立即从ModelOne
中获得关系计数。我还添加了一个属性$return\u 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');
}
}
然后,我添加了两个helper函数,一个递归获取给定父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\u two\u count
,因为它是在调用withCount('model\u two')
时创建的。另外,当调用带有('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();
}
}
这将获得您想要的良好输出:
所以,我找到了解决办法,这是给你们所有可能在同一个问题上挣扎的人的
首先,在我的ModelOne
中,我添加了withCount('model_two')
,这样我可以立即从ModelOne
中获得关系计数。我还添加了一个属性$return\u 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');
}
}
然后,我添加了两个helper函数,一个递归获取给定父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\u two\u count
,因为它是在调用withCount('model\u two')
时创建的。另外,当调用带有('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();
}
}
这将获得您想要的良好输出: