2014-09-13 33 views
0

兄弟姐妹之間的關係有很多很多的自我關係。因此,對於多對多的自我關係,我們可以在模型中定義兩個函數:Laravel兄弟姐妹之間的親密關係

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的兄弟。

那麼,如何獲得所有學生兄弟姐妹的收集?

+0

所以它更像是'relative'不'sibling',對不對?你會喜歡多深?請注意,它可以變成類似於「每個學生都是其他人的親戚」的東西。 – 2014-09-16 08:12:10

回答

0

我假設你有一個學生模型,與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()函數,直到耗盡兄弟姐妹。

在學生模型,定義了兩個功能:

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()。)

從那裏,您可以根據需要將集合轉換爲數組或排序等。

+0

您不需要這段代碼,只需在關係上調用'with'即可使其遞歸。然而,這不是要走的路,因爲它可能很容易超過功能嵌套限制。 – 2014-09-16 08:05:30

+0

@JarekTkaczyk你可以用'with'來演示解決這個問題嗎?我看不出它會如何取回第一組兄弟姐妹之外的任何東西。 「如何」穿過整個兄弟姐妹鏈? (真實世界的限制會阻止這種遞歸的次數超過十次。) – damiani 2014-09-16 12:00:21

+0

你去找夥伴。並告訴我,「真實世界的限制會妨礙......你是什麼意思?」? – 2014-09-16 16:58:43

1

遞歸關係,能做到這一點,但它可能會導致無限循環(函數嵌套限制錯誤)

反正這是如何建立這樣的關係:

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

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

然後調用,像這樣簡單:

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

我認爲使用Eager Loading遞歸可能會在我正在構建的應用程序中發生危險。因爲,沒有辦法知道當前學生在遞歸中的兄弟姐妹已經找到了。所以,在某些情況下,會造成無限循環。無論如何,謝謝你的回答。 – Debiprasad 2014-09-17 14:31:41