web-dev-qa-db-fra.com

Relation éloquente parent-enfant sur le même modèle

J'ai un modèle CourseModule, et chacun des éléments est lié au même modèle.

Structure de la base de données:

 enter image description here

Relation dans le modèle:

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

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

J'ai essayé ce qui suit, mais cela ne renvoie qu'un seul niveau de relation.

A tenté:

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

J'essaie de créer une sortie JSON comme suit,

Production attendue:

[
  {
    "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": []
              }
            ]
          }
        ]
      }
    ]
  }
]

Je ne comprends pas comment obtenir les objets enfants intérieurs.

14
Kiran LM

Si vous avez une profondeur inconnue comme celle-là, vous devrez obligatoirement récupérer les enfants.

Une autre option consiste à utiliser le modèle nested sets au lieu du modèle adjacency list. Vous pouvez utiliser quelque chose comme le package baum/baum pour Laravel pour les ensembles imbriqués.

"Un ensemble imbriqué est un moyen intelligent d'implémenter une arborescence ordonnée qui permet des requêtes rapides et non récursives." - https://github.com/etrepat/baum

Avec ce package, vous disposez de méthodes telles que getDescendants pour obtenir tous les enfants et les enfants imbriqués et toHierarchy pour obtenir une hiérarchie complète.

Wikipedia - Modèle d'ensemble imbriqué

Baum - Modèle de jeu imbriqué pour l'ORM Eloquent de Laravel

Gestion des données hiérarchiques dans MySQL

5
lagbox

Vous devez utiliser with('children') dans la relation enfants Et with('parent') dans les relations parentales.

Pour que votre code soit récursif:

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');
}

Remarque: Assurez-vous que votre code contient une ou plusieurs des conditions de sortie, sinon il se retrouvera dans une boucle sans fin.

10
Shyam Achuthan

ici est la réponse qui peut vous aider

Je pense que vous devez le faire récursivement pour récupérer un arbre entier:

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

Fonction récursive

Cela peut vous aider selon vos besoins,

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
Sagar Naliyapara

Vous pouvez toujours créer votre propre fonction récursive, dans mon cas je fais le code comme suit. 

<?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;

    }

}
2
Pablo Morales