Relazione molti a molti in un modello dati con Laravel Eloquent ORM

laravel eloquent model

Nella modellazione dei dati Entity Relationship, esiste una relazione molti a molti quando più record in un’entità possono essere associati a più record in un’altra entità e viceversa.

Questo tipo di relazione è rappresentato utilizzando una tabella di join che include chiavi esterne che fanno riferimento alle chiavi primarie delle entità correlate.

Vediamo come eloquent di laravel ci aiuta nella gestione della relazione molti a molti, semplificandone le query.

Tempo di lettura stimato: 5 minuti

Relazione Molti a Molti

Una relazione molti a molti non è una proprietà dei dati stessi, ma della relazione tra le tabelle. Garantisce che ogni riga di una tabella corrisponda a più di una riga di un’altra tabella, e viceversa.

È una rappresentazione dell’associazione tra due entità in cui un’entità (il lato “molti-uno”) può essere collegata a più istanze di un’altra entità (il lato “molti-due”), e ciascuna istanza sul lato “molti-due” può essere collegata a più istanze dell’entità sul lato “molti-uno”.

Se vuoi approfondire il caso della relazione uno a molti con eloquent di Laravel, allora leggi questo articolo Relazione uno a molti in un modello dati con Laravel Eloquent ORM

Consideriamo ad esempio le entità Studente e Corso. Una relazione molti a molti tra queste due entità significherebbe che: Un singolo studente può iscriversi a più corsi. Ad un singolo corso possono essere iscritti più studenti.

Per implementarlo in un database, dovremmo creare una tabella di join, spesso chiamata tabella associativa o di giunzione, che potrebbe essere denominata Studet_Subject. Questa tabella avrà almeno due campi: Student_Id e Subject_Id. Ogni record nella tabella Studet_Subject rappresenta un collegamento tra uno studente e un corso, indicando che lo studente è iscritto a quel corso.

eloquent many to many
Relazione molti a molti

Laravel Eloquent Relazione Molti a Molti

Laravel Eloquent fornisce metodi completi per gestire le relazioni tra le tabelle del database. In questo articolo vedremo la relazione molti a molti, e come impostarla.

In una relazione molti a molti, un’entità (chiamiamola A) può essere associata a più istanze di un’altra entità (chiamiamola B). Allo stesso modo, ciascuna istanza di B appartiene a più istanze di A.

Ad esempio, consideriamo uno scenario in cui:

  • uno studente ha più materie da studiare, e
  • ogni singola materia può essere studiata da più studenti.
Creazione Tabelle con Migration di Laravel

Creiamo le tabelle del database necessarie per gli studenti, le materie e la tabella pivot student_subject. Possiamo utilizzare le migration di Laravel per creare queste tabelle. Ecco come:

// Create the 'students' table
Schema::create('students', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

// Create the 'subjects' table
Schema::create('subjects', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

// Create the 'student_subject' pivot table
Schema::create('student_subject', function (Blueprint $table) {
    $table->id();
    $table->foreignId('student_id');
    $table->foreignId('subject_id');
    $table->string('grade')->nullable();
    $table->timestamps();
});

Eseguiamo le migrations utilizzando il comando di linea php artisan migrate.

Impostazione relazione Molti a molti

Definiamo le relazioni nei modelli Student e Subject, usiamo i comandi Artisan

php artisan make:model Student
php artisan make:model Subject

Modifichiamo il file Student.php con il metodo belongsToMany

// app/Models/Student.php
class Student extends Model
{
    public function subjects()
    {
        return $this->belongsToMany(Subject::class);
    }
}

Modifichiamo il file Subject.php con il metodo belongsToMany

// app/Models/Subject.php
class Subject extends Model
{
    public function students()
    {
        return $this->belongsToMany(Student::class);
    }
}

Esempio CRUD uno a molti

Inserire

Creiamo il metodo store_subject nel controller StudentController.php per creare le materie per uno studente. Supponiamo che il metodo store_subject ha due parametri: il nome dello studente e le sue materie:

// app/Http/Controllers/StudentController.php
//
// $name: student
// $subject: array
public function store_subject(string $name, array $subjects)
{
    $student = new Student;
    $student->name = $name;
    $student->save(); 

    // Create subjects
    // $subjects = ['English', 'Math', 'Science'];
    foreach ($subjects as $subjectName) {
        $subject = new Subject;
        $subject->name = $subjectName;
        $subject->save();

        // Attach the subject to the student
        $student->subjects()->attach($subject->id); 
    }

    return "Subjects created for student: {$student->id}";
}
Leggere

Per leggere le materie associate a uno studente

public function getsubjects(int $id_student)
{
    $student = Student::find($id_student); 

    $associatedSubjects = $student->subjects;
    // Do something with $associatedSubjects
}

Se non ci sono argomenti associati, il risultato sarà vuoto.

Se volessimo sapere tutti gli studenti associati a una materia avremmo:

public function getstudents(int $id_subject)
{
    $subject= Subject::find($id_subject); 

    $associatedStudents = $subject->students;
    // Do something with $associatedStudents 
}
Sincronizzare associazioni (Cancellare o Aggiungere)

Eloquent mette a disposizione il metodo di sincronizzazione per costruire associazioni molti a molti. Il metodo di sincronizzazione accetta una matrice di identificatori da inserire nella tabella intermedia. Tutti gli ID che non si trovano nell’array specificato verranno rimossi dalla tabella intermedia. Quindi, una volta completata questa operazione, nella tabella intermedia esisteranno solo gli ID nell’array specificato:

// the student $student have 1,2,3,4,5 subjects
$student->subjects()->sync([1, 2, 3, 4, 5]);

Possiamo passare anche ulteriori valori di tabella intermedi, ognuno associato a uno specifico ID, o anche associati a tutti gli ID in array:

// subject 1 has expires value true
$student->subjects()->sync([1 => ['expires' => true], 2, 3]);


// all subjects have active value true
$student->subjects()->syncWithPivotValues([1, 2, 3], ['active' => true]);

Per sincronizzare senza disassociare, puoi utilizzare il metodo syncWithoutDetaching che ci consente di lasciare inalterate le associazioni non specificate:

$student->subjects()->syncWithoutDetaching([1, 2, 3]);

Una forma ci cancellazione è anche quella che prevede di attivare/disattivare una associazione, infatti eloquent fornisce anche un metodo che “attiva/disattiva” lo stato di collegamento degli ID. Se l’ID specificato è attualmente collegato, verrà scollegato. Allo stesso modo, se è attualmente scollegato, verrà collegato:

$student->subjects()->toggle([1, 2, 3]);
Aggiornare associazioni

Per aggiornare una riga esistente nella tabella intermedia della relazione, possiamo utilizzare il metodo updateExistingPivot. Questo metodo accetta la chiave esterna del record intermedio e una serie di attributi da aggiornare:

// the student $student have 1,2,3,4,5 subjects
$student= Student::find(1);
 
$student->subjects()->updateExistingPivot($subjectId, [
    'active' => false,
]);

Letture Correlate

Ercole Palmeri

Autore