同一模型上的Eloquent父子关系

30

我有一个模型CourseModule,每个条目都与相同的模型相关。

数据库结构:

输入图像描述

模型关系:

    public function parent()
    {
        return $this->belongsTo('App\CourseModule','parent_id')->where('parent_id',0);
    }

    public function children()
    {
        return $this->hasMany('App\CourseModule','parent_id');
    }

我尝试了以下方法,但它只返回了一个层级的关系。

尝试过的方法:

CourseModule::with('children')->get();

我希望你能够创建一个类似以下格式的JSON输出:

期望输出结果:

[
  {
    "id": "1",
    "parent_id": "0",
    "course_id": "2",
    "name": "Parent",
    "description": "first parent",
    "order_id": "1",
    "created_at": "-0001-11-30 00:00:00",
    "updated_at": "-0001-11-30 00:00:00",
    "children": [
      {
        "id": "2",
        "parent_id": "1",
        "course_id": "2",
        "name": "Child 1",
        "description": "child of parent",
        "order_id": "2",
        "created_at": "-0001-11-30 00:00:00",
        "updated_at": "-0001-11-30 00:00:00",
        "children": [
          {
            "id": "3",
            "parent_id": "2",
            "course_id": "2",
            "name": "Child2",
            "description": "child of child1",
            "order_id": "2",
            "created_at": "-0001-11-30 00:00:00",
            "updated_at": "-0001-11-30 00:00:00",
            "children": [
              {
                "id": "4",
                "parent_id": "3",
                "course_id": "2",
                "name": "Child 3",
                "description": "child of child 2",
                "order_id": "2",
                "created_at": "-0001-11-30 00:00:00",
                "updated_at": "-0001-11-30 00:00:00",
                "children": []
              }
            ]
          }
        ]
      }
    ]
  }
]

我不明白如何获取内部子对象。

6个回答

34

在子关系中应使用with('children'),在父关系中应使用with('parent')

为了使您的代码递归:

public function parent()
{
    return $this->belongsTo('App\CourseModule','parent_id')->where('parent_id',0)->with('parent');
}

public function children()
{
    return $this->hasMany('App\CourseModule','parent_id')->with('children');
}

注意:确保你的代码有某种退出条件,否则它会陷入无休止的循环。


它可以工作!在第一个集合中,我有一棵链式树,但是同样的子项作为父集合重复出现。我不想再次将子项作为根集合。是否有任何解决方案或者我做错了什么? - Shahbaz Ahmed
找到了解决方案 $data = CourseModule::with('children')->where('parent_id', 0) - Shahbaz Ahmed
我试图按层次结构显示结果,但无法实现。我尝试了类似于这样的代码 @foreach ($accountHeads as $accountHead) @foreach ($accountHead->children as $children) <option value="{{ $children->id }}">{{ $children->name }}</option> @endforeach @endforeach ,但它只显示那些 parent_id = 1 的内容。 - Rashed Hasan

10

如果您的深度是未知的,那么您需要递归获取子级。

另一个选项是使用嵌套集模型而不是邻接表模型。您可以使用类似于 Laravel 的 baum/baum 包来处理嵌套集。

"嵌套集是一种智能实现有序树的方式,允许快速、非递归查询。" - https://github.com/etrepat/baum

使用此包,您可以使用像 getDescendants 这样的方法获取所有子代和嵌套子代,并使用 toHierarchy 获取完整的树形结构。

Wikipedia - 嵌套集模型

Baum - Laravel 的 Eloquent ORM 的嵌套集模式

在 MySQL 中管理分层数据


嗨,CourseModule::whereId($id)->first()->getDescendantsAndSelf()->toHierarchy() 只返回单个节点,我需要对模型进行任何更改吗?我正在使用如上所示的单个表。 - Kiran LM

9

这里是可以帮助您的答案。

我认为您需要递归地进行操作,以检索整个树:

$data = CourseModule::with('child_rec');

递归函数

根据您的需求,以下内容可能会有所帮助:

public function child()
{
   return $this->hasMany('App\CourseModule', 'parent');
}
public function children_rec()
{
   return $this->child()->with('children_rec');
   // which is equivalent to:
   // return $this->hasMany('App\CourseModule', 'parent')->with('children_rec);
}
// parent
public function parent()
{
   return $this->belongsTo('App\CourseModule','parent');
}

// all ascendants
public function parent_rec()
{
   return $this->parent()->with('parent_rec');
}

4
你的模型关系应该像这样。
     // parent relation
     public function parent(){

        return $this->belongsTo(self::class , 'parent_id');
    }
    //child relation
     public function children()
    {
        return $this->hasMany(self::class ,'parent_id');
    }
    public function ascendings()
    {
        $ascendings = collect();

        $user = $this;

        while($user->parent) {
            $ascendings->push($user->parent);

            if ($user->parent) {
                $user = $user->parent;
            }
        }

        return $ascendings;
    }



    public function descendings()
    {
        $descendings = collect();
        $children = $this->children;

        while ($children->count()) {

            $child = $children->shift();

            $descendings->push($child);

            $children = $children->merge($child->children);

        }
        return $descendings;
    }

请问,您能否在回答中加入更详细的解释?这将对理解非常有帮助。谢谢! - vezunchik

4

模型功能:

public function Children()
{ 
    return $this->hasMany(self::class, 'Parent', 'Id')->with('Children');
} 

控制器函数:

Menu::with("Children")->where(["Parent" => 0])->get(); 

2
您可以随时创建自己的递归函数,我在这里的做法如下所示的代码。
<?php
declare(strict_types=1);

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Akmeh\Uuid;

/**
 * Class Location
 * @package Domain\Models
 */
class Location extends Model
{
    use Uuid;

    /**
     * Indicates if the IDs are auto-incrementing.
     *
     * @var bool
     */
    public $incrementing = false;
    public $timestamps = false;

    /**
     * @param string $id
     * @param array $tree
     * @return array
     */
    public static function getTree(string $id, array $tree = []): array
    {
        $lowestLevel = Location::where('id', $id)->first();

        if (!$lowestLevel) {
            return $tree;
        }

        $tree[] = $lowestLevel->toArray();

        if ($lowestLevel->parent_id !== 0) {
            $tree = Location::getTree($lowestLevel->parent_id, $tree);
        }

        return $tree;

    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接