Laravel雄辩的兄弟姐妹关系

时间:2014-09-13 09:47:44

标签: laravel model eloquent relationships

兄弟姐妹的关系是多对多的自我关系。因此,对于多对多的自我关系,我们可以在模型中定义两个函数:

public function siblings()
{
    return $this->belongsToMany('Student', 'student_sibling', 'student_id', 'sibling_id');
}

public function siblingOf()
{
    return $this->belongsToMany('Student', 'student_sibling', 'sibling_id', 'student_id');
}

第一个返回学生兄弟姐妹的学生。兄弟姐妹也是如此。因此,第二个返回学生是兄弟姐妹的学生。

因此,我们可以合并两个馆藏,以获得学生兄弟姐妹的列表。这是我在控制器方法中的代码:

    $siblingOf = $student->siblingOf;

    $siblings = $student->siblings;

    $siblings = $siblings->merge($siblingOf);

但还有更多。兄弟姐妹关系是一种与朋友关系不同的连锁关系。这意味着,如果X是Y的兄弟,Y是Z的兄弟,则Z是X的兄弟。

那么,如何收集所有兄弟姐妹的学生集合?

3 个答案:

答案 0 :(得分:1)

我假设你有一个Student模型,其中student_id是你的主键,而一个数据透视表看起来像这样:

+---------+------------+------------+
| id (PK) | student_id | sibling_id |
+---------+------------+------------+
| 1       | 1          | 2          |
| 2       | 2          | 1          |
| 3       | 3          | 4          |
| 4       | 4          | 2          |
| 5       | 6          | 5          |
+---------+------------+------------+

在这个例子中,我们希望能够辨别出1,2,3和4是彼此的所有兄弟姐妹。 5和6也是兄弟姐妹。

解决此问题的一种方法是在模型中收集两个belongsToMany()关系的结果 - 就像在问题中一样 - 然后递归迭代结果,继续检查belongsToMany()直到我们的兄弟姐妹都用完为止。

在Student模型中,定义两个函数:

public function getAllSiblings(){

    // create a collection containing just the first student
    $this->siblings = $this->newCollection()->make($this);

    // add siblings (recursively) to the collection
    $this->gatherSiblings($this->student_id);

    // OPTIONAL: remove the first student, if desired
    $this->siblings->shift();

    return($this->siblings);
}

private function gatherSiblings($student_id){

    $checkStudent = Student::find($student_id);

    if ($checkStudent) {
        // get related siblings from model, combine them into one collection
        $siblingOf = $checkStudent->siblingOf()->get();
        $siblings = $checkStudent->siblings()->get();
        $siblings = $siblings->merge($siblingOf);

        // iterate over the related siblings
        $siblings->each(function($sibling)
        {
            // if we've found a new sibling who's 
            // not already in the collection, add it
            if(!$this->siblings->contains($sibling->student_id)) {
                $this->siblings->push($sibling);

                // look for more siblings (recurse)
                $this->gatherSiblings($sibling->student_id);
            };
        });
        return;
    }
}

在您的控制器中,找到初始学生,然后从学生呼叫getAllSiblings()

$student = Student::find($id);
$siblings = $student->getAllSiblings();

结果是与原始学生的所有兄弟姐妹的集合。所以,如果你为学生1运行这个,你会得到一个包含学生2,3和4的集合。(如果你更愿意将原来的学生作为兄弟姐妹集合的一部分,那么为1运行它会返回1, 2,3和4,只需删除optional中的getAllSiblings()步骤。)

从那里,您可以根据需要将集合转换为数组或排序等。

答案 1 :(得分:1)

递归关系可以做到这一点,但它可能会导致无限循环(函数嵌套限制错误)

无论如何,这是如何设置这种关系:

public function siblingsRecursive()
{
    return $this->siblings()->with('siblingsRecursive');
}

public function siblings()
{
    return $this->belongsToMany('Student', 'siblings');
}

然后你打电话,就像这样简单:

$students = Student::with('siblingsRecursive');

答案 2 :(得分:0)

我想你可能想要的是这个

 public function siblings() {
    return $this->hasMany(self::class, 'parent_id', 'parent_id');
 }