2014-09-13 1 views
0

Отношения для братьев и сестер - это много для многих отношений. Так, многие ко многим себе отношения, мы можем определить две функции в модели:Laravel Eloquent Отношения для братьев и сестер

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', верно? Насколько глубоким вы хотели бы быть?Имейте в виду, что это может стать чем-то вроде «каждый ученик - это все родственники в некотором смысле». –

ответ

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' в отношении, чтобы сделать его рекурсивным. Однако это не путь, так как он может легко превышать ограничение вложенности функции. –

+0

@JarekTkaczyk вы можете продемонстрировать это, используя 'with'? Я не вижу, как он будет извлекать что-либо за пределы первого набора братьев и сестер. Как «с» пересекают всю цепочку братьев и сестер? (И ограничения в реальном мире помешали бы этому пересказывать больше, чем, скажем, дюжину раз.) – damiani

+0

там вы идете мат. И скажите мне, что вы подразумеваете под «ограничениями реального мира»? –

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