Prenons le cas d’une table familles avec des enregistrements liés parent/enfant sur plusieurs niveaux
id | nom | id_parent ----------------------------- 1 | grand parent | null 2 | parent | 1 3 | enfant 1 | 2 4 | enfant 2 | 2 etc...
Si on crée une relation simple dans le model, on obtient uniquement les enfants sur un seul niveau. On va créer une méthode qui s’appelle elle même
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Famille extends Model { public function childrens() { return $this->hasMany(Famille::class, 'id_parent', 'id'); } public function recursiveChildren() { return $this->childrens()->with('recursiveChildren'); // si vous voulez trier par nom return $this->childrens()->orderBy('nom')->with('recursiveChildren'); } }
La requête eloquent pour sortir un résultat correcte est la suivante
Famille::with('recursiveChildren')->whereNull('id_parent')->get()
On utilise le with() pour forcer l’exécution de la relation pour chaque enregistrement et on filtre sur le id_parent sur null pour commencer uniquement sur le 1er niveau
On obtient ce résultat
=> Illuminate\Database\Eloquent\Collection { all: [ App\Models\Famille { id: 1, nom: "grand parent", id_parent: null, recursiveChildren: Illuminate\Database\Eloquent\Collection { all: [ App\Models\Famille { id: 2, nom: "parent", id_parent: 1, recursiveChildren: Illuminate\Database\Eloquent\Collection { all: [ App\Models\Famille { id: 3, nom: "enfant 1", id_parent: 2, recursiveChildren: Illuminate\Database\Eloquent\Collection { all: [], }, }, App\Models\Famille { id: 4, nom: "enfant 2", id_parent: 2, recursiveChildren: Illuminate\Database\Eloquent\Collection { all: [], }, }, ], }, }, ], }, }, ], }
Maintenant on veut afficher le résultat. Il va falloir créer une sous-vue pour la récursivité.
Controller
public function index(){ $familles = Famille::with('recursiveChildren')->whereNull('id_parent')->orderBy('nom')->get(); return view('famille', compact('familles')); }
Vue: famille.blade.php
<select> <option></option> @php $tab = ''; @endphp @foreach ( $familles as $e ) @include('famille-item', ['famille'=>$e, 'tab'=>$tab]) @endforeach </select>
Vue: famille-item.blade.php
<option>{!! $tab !!}{{ $famille->nom }}</option> @if(isset($famille->recursiveChildren) and count($famille->recursiveChildren)) @php // adaptez comme vous le souhaitez $tab .= '⋅ '; @endphp @foreach ($famille->recursiveChildren as $element) @include('visu.groupe-item', ['famille'=>$element, 'tab'=>$tab]) @endforeach @endif
Pour un affichage en liste avec ul et li
Vue: famille.blade.php
<ul> @foreach ( $familles as $e ) @include('famille-item', ['famille'=>$e]) @endforeach </ul>
Vue: famille-item.blade.php
<li>{!! $tab !!}{{ $famille->nom }}</li> @if(isset($famille->recursiveChildren) and count($famille->recursiveChildren)) <ul> @foreach ($famille->recursiveChildren as $element) @include('visu.groupe-item', ['famille'=>$element]) @endforeach </ul> @endif