This is Part 3 of our Laravel 8 Eloquent Relationships Tutorial
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('AppModelsSubject');
}
in Models/Subject.php
public function student()
{
return $this >belongstoMany('AppModelsStudent');
}
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:
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:
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:
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
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
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:
Now go to http://localhost:8000/students to see if the the student is now only associated with 2 subjects
Result:
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:
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:
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('AppModelsSubject','student_subject','student_id','subject_id');
}
go to Models/Subject.php
public function student()
{
return $this >belongstoMany('AppModelsStudent','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('AppModelsSubject','student_subject','student_id','subject_id')
>withPivot('grade');
}
go to Models/Subject.php
public function student()
{
return $this >belongstoMany('AppModelsStudent','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);