Laravel 8- Eloquent Relationships Tutorial - Many to Many Relationship
Tags: php, laravel, erd, beginners
Published: 2022-02-06 13:46:26

**This is Part 3 of our Laravel 8 - Eloquent Relationships Tutorial**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xbzj35dkkolv4io6fiz1.PNG)

Let's start by creating the database table necessary
`php artisan make:migration create_subjects_table`
`php artisan make:migration create_student_subject_table`


go to app/database/migrations:
subjects:

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

```
Schema::create('student_subject', function (Blueprint $table) {
            $table->id();
            $table->foreignId('student_id');
            $table->foreignId('subject_id');
            $table->string('grade')->nullable();
            $table->timestamps();
        });
```
copy and save

run migration to create tables
`php artisan migrate`

check in your database if successful

Now let's create the model of comments
`php artisan make:model Subject`

Many to Many Relationships

Go to app/Models and open the student model and the comment models

define the many to many relationship
in Models/Student.php
```
public function subject()
    {
        return $this->belongstoMany('App\Models\Subject');
    }
```

in Models/Subject.php
```
public function student()
    {
        return $this->belongstoMany('App\Models\Student');
    }
```
_this will define the relationship between the two models_

using the StudentController we made in part 1 lets create the function to create 3 subjects under 1 student

go to app/Http/Controllers/StudentController

```
public function store_subject(){

        $subject = new Subject;
        $subject->name = 'English';
        $subject->save();

        $subject = new Subject;
        $subject->name = 'Math';
        $subject->save();

        $subject = new Subject;
        $subject->name = 'Science';
        $subject->save();

        dd($subject);
    }
```

> this is for example purposes of creating multiple subjects only

create routes in app/routes/web.php

```
Route::get('/subjects/store', [StudentController::class,'store_subject'])->name('storeSubject');
```
in your browser go to http://localhost:8000/students/store/comment to create 3 entry in the database

it should look similar to:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vumuo19ud9yff6gtzm0y.PNG)

Using the two tables students and subjects lets save info to the student_subject table

check first if connection is successful by doing this

```
public function index(){
        $student = Student::find(1);
        dd($student->subject);
    }
```
Result should be empty and similar to this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/877aacz8njsnru0q73zt.PNG)
> it is empty because there are no associated subjects for any user

Now let's create associations from subjects to student

go to app/Http/Controllers/StudentController

```
public function store_student_subject(){

        $student = Student::find(1);
        
        $student->subject()->attach(1);

        dd($student);
    }
```

create routes in app/routes/web.php

```
Route::get('/students/store/subject', [StudentController::class,'store_student_subject'])->name('storeStudentSubject');
```

go to http://localhost:8000/students/store/subject to run the code

it should look similar to:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/scjnvwbag6t5biqn0hvm.PNG)

> Hurray you have successfully attached one subject to one student!

Now go to http://localhost:8000/students to see if the the subject is connected to the student

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4hvm6y9b7dhnd2ypvut.PNG)

Now let's create associations from subjects to student by passing an array

go to app/Http/Controllers/StudentController
```
public function store_student_subject(){
        $student = Student::find(1);
        $student->subject()->attach([2,3]);
        dd($student);
    }
```
The result would be 2 rows of newly created associations for student id 1 with subject id 2 and 3

Now go to http://localhost:8000/students to see if the the student is now associated with 3 subjects

Result:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h0gnsgu44raphmvuedba.PNG)

> Now that we know how to add associations let's try and remove one!

Lets create the controller and route to detach associations

go to app/Http/Controllers/StudentController

```
public function detach_student_subject(){
        $student = Student::find(1);    
        $student->subject()->detach(1);
        dd($student);
    }
```

create routes in app/routes/web.php

```
Route::get('/students/detach/subject', [StudentController::class,'detach_student_subject'])->name('detachStudentSubject');
```
go to http://localhost:8000/students/detach/subject to run the code

it should look similar to:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yo6y0uu7ekot9so274dv.PNG)

Now go to http://localhost:8000/students to see if the the student is now only associated with 2 subjects
Result:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m2fieerjjjm8ynxw5yba.PNG)

> Hurray you have successfully detached one subject to one student!

> Now lets try to use sync to simultaneously attack and detach subjects using 1 script

To test it out let's first add one more subject to be attached to the student

go to app/Http/Controllers/StudentController

```
public function store_subject(){
        $subject = new Subject;
        $subject->name = 'History';
        $subject->save();
        dd($subject);
    }
```
go to http://localhost:8000/subjects/store to run the code

> You should now have 4 subjects

And now lets try and use sync

go to app/Http/Controllers/StudentController

```
public function store_subject(){
        $subject = new Subject;
        $subject->name = 'History';
        $subject->save();
        dd($subject);
    }
```
create routes in app/routes/web.php
```
Route::get('/students/sync/subject', [StudentController::class,'sync_student_subject'])->name('syncStudentSubject');
```
> Now the associations should only be subject id 2 and 3 but after we run this code the associations should be for subject 1, 2 and 4

> 1 and 4 was attached while 3 was dettached and 2 remained using sync

go to http://localhost:8000/students/sync/subject to run the code

then 

go to http://localhost:8000/students to see if the the student is now associated with subjects 1, 2 and 4

Result:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sd1k5ee6u0606jak7bhc.PNG)

> Hurray you have successfully used sync to attach and detach subject to one student!

Now let's try toggle and do this quickly:
Create routes and controller:

```
public function toggle_student_subject(){
        $student = Student::find(1);    
        $student->subject()->toggle([1,2,3,4]);
        dd($student);
    }
...
Route::get('/students/toggle/subject', [StudentController::class,'toggle_student_subject'])->name('toggleStudentSubject');
```
Toggle is used to do the opposite of the current status of a relationship.

For example:
Since 1,2 and 4 are currently attached, when you use toggle it will be detached and 3 will be attached.

Run this http://localhost:8000/students/toggle/subject and this http://localhost:8000/students and the result should be:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n7owiil9yy5fvm337gns.PNG)

For best practices lets add the name of the pivot table to the model, and specify the two foreign keys with it (3rd = local key, 4th = foreign key)

go to Models/Student.php
```
public function subject()
    {
        return $this->belongstoMany('App\Models\Subject','student_subject','student_id','subject_id');
    }
```

go to Models/Subject.php
```
public function student()
    {
        return $this->belongstoMany('App\Models\Student','student_subject','subject_id','student_id');
    }
```
> It should work just like how it worked the first time!

Now let's try and add one more column in the pivot table.
Take note that we have already 1 extra column grade and we will now use it.

go to Models/Student.php
```
public function subject()
    {
        return $this->belongstoMany('App\Models\Subject','student_subject','student_id','subject_id')
            ->withPivot('grade');
    }
```

go to Models/Subject.php
```
public function student()
    {
        return $this->belongstoMany('App\Models\Student','student_subject','subject_id','student_id')
            ->withPivot('grade');
    }
```

Now lets try and add grades to the student_subject table
Add this in controller and routes

```
public function grade_student_subject(){
        $student = Student::find(1);
        $subject = Subject::find(2);    
        $student->subject()->save($subject,['grade'=>90]);
        dd($student);
    }
...
Route::get('/students/grade/subject', [StudentController::class,'grade_student_subject'])->name('gradeStudentSubject');
```

> This will add a new row grade 90 to subject 2 because we are using the "save" method #note that if you use subject 3 then it will add a new row with subject 3 and grade and not replace the current subject 3 with no grade

Run this http://localhost:8000/students/grade/subject and this http://localhost:8000/students and the result should be:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x036z5v4800jj93yjx6j.PNG)

> Now lets use update!
Update Method
```
public function grade_student_subject(){
        $student = Student::find(1);
        $subject = Subject::find(2);    
        $student->subject()->updateExistingPivot($subject,['grade'=>95]);
        dd($student);
    }
```
Result should be 95!
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xrphs2r8aculvk0vzkh1.PNG)

Now let's query!

**Students who have subjects**
```
public function index(){
        $student = Student::has('subject')->get();
        dd($student);
    }
```
**Students who does not have subjects**
```
public function index(){
        $student = Student::doesntHave('subject')->get();
        dd($student);
    }
```
**Students which have a particular subject**
```
public function index(){
        $student = Subject::with('student')->where('id',2)->get();
        dd($student);
    }
```
**Fetch count of subjects each student has**
```
public function index(){
        $student = Student::withCount('subject')->get();
        dd($student);
    }
```
**Fetch count of subjects each student has order by subject_count in descending order**
```
public function index(){
        $student = Student::withCount('subject')->orderBy('subject_count','desc')->get();
        dd($student);
    }
```
**Fetch students with 2 or more subjects**
```
public function index(){
        $student = Student::has('subject','>=',2)->get();
        dd($student);
    }
```
**Fetch students with grade >= 90 , we will use grade in Pivot Table**
```
public function index(){
        $student = Student::with('subject')
        ->whereHas('subject', function($query){
            $query->where('grade','>=',90);
        })->get();
        dd($student);
    }
```
> Awesome we've completed lots and lots of exercises!
> Stay tuned for part 4 of this series - hasOneThrough and hasManyThrough Relationship!