I am using Laravel 5 and am trying to get my head round relationships.
I have 2 tables, students and rooms. Each room can have many students, and each student can have many rooms.
Would this be a Many to Many relationship in both directions? Would I need a pivot table to achieve this?
Yes, what you describe is a many-to-many relationship, and for that you'll need a pivot table.
Your three tables would look like this: (this might look different from your actual tables)
students
id (primary key)
name
age
rooms
id (primary key)
room_size
bedroom_count
Note: by default, the name of the pivot table is composed of both model names (in singular form), in alphabetical order. So in this case: Student + Room = room_student.
room_student (pivot table)
room_id (foreign key to 'rooms')
student_id (foreign key to 'students')
Pivot table migration:
class CreateRoomStudentTable extends Migration
{
public function up()
{
Schema::create('room_student', function (Blueprint $table) {
$table->unsignedInteger('room_id');
$table->unsignedInteger('student_id');
// Primary key
$table->primary(['room_id', 'student_id']);
// Both foreign keys
$table->foreign('room_id')
->references('id')
->on('rooms')
->onDelete('cascade');
$table->foreign('student_id')
->references('id')
->on('students')
->onDelete('cascade');
});
}
// ...
Room and Student models:
class Room extends Model {
// ...
public function students()
{
$this->belongsToMany(App\Student::class);
}
}
class Student extends Model {
// ...
public function rooms()
{
$this->belongsToMany(App\Room::class);
}
}
Would this be a Many to Many relationship in both directions?
yes you need to Many to Many relationship in both directions
Would I need a pivot table to achieve this?
yes
you can see more about Many to Many relationship here
Yes you can implement many to many relationship and you will definitely need pivot table for implementing many to many relationship.
In this case you can create pivot table like room_student and add the room_id and student_id columns in it. then just use define relationship using belongsToMany method in your models and remember to use the attach method whereever you want to attach the functionality.
You need a pivot table.
About that, you can find out more from here:
ManyToManyRelationship
Related
I have two tables products and orders which are linked by a pivot table order_product with the id of each table. But I also want to add an amout column to the pivot table. How can I do this with laravel Voyager?
Easily just define it in your migration file of order_product and access it from relation function as bellow:
Schema::create('order_product', function (Blueprint $table) {
$table->unsignedBigInteger('order_id');
$table->unsignedBigInteger('product_id');
$table->unsignedInteger('amount');
});
and for example in your product model:
public function orders()
{
return $this->belongsToMany(Order::class)
->withPivot('amount');
}
This app has a Bug model and a User model. Users can "follow" Bugs. This seems like a pivot table. What's the simplest way to implement this with a migration and Model relationship? I'm thinking along the lines of a followers table:
Schema::create('followers', function (Blueprint $table) {
$table->increments('id');
$table->uuid('bug_id');
$table->uuid('user_id');
$table->index(['bug_id', 'user_id']);
$table->timestamps();
$table->softDeletes();
});
Where I'm mostly stumped is the followers relationship in the Bugs Model. This is where I'm currently at:
public function followers()
{
return $this->belongsToMany(User::class, 'followers', 'bug_id', 'user_id');;
}
This really doesn't seem right. New to eloquent pivot tables, so really appreciate the help!
You are looking for a many-to-many relationship which requires an intermediary table bug_follower just as you created one and you also need to create a relationship from Bug to Follower as you did, but also create the relationship from Follower to Bugs. You are on the right track.
Overall you will have 2 models: Bug, Follower.
You will also have 3 tables: bugs, followers, bug_follower
And 2 relationships from Bug and Follower to each other
EDIT: This is how your relationship needs to look like:
public function followers()
{
return $this->belongsToMany(User::class, 'followers', 'bug_id', 'user_id');
}
You can check more about subject in the docs.
What is the difference between defining the relation between 2 tables within the two models and defining it in the proper migration file?
For example, I want a many to one relationship between the table cars and the table persons.
Option 1: I define the relation in the models
Model Person:
class Person extends Model
{
public function cars()
{
return $this->hasMany('App\Car');
}
}
Model Car:
class Car extends Model
{
public function persons()
{
return $this->belongsToMany('App\Person');
}
}
Option 2: I define the relation in the migration
class CreateCarsTable extends Migration
{
public function up()
{
Schema::create('cars', function (Blueprint $table) {
$table->increments('id');
$table->integer('person_id')->references('id')->on('person');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('cars');
}
}
Thank you for your help.
From the docs
Eloquent relationships are defined as methods on your Eloquent model classes. Since, like Eloquent models themselves, relationships also serve as powerful query builders, defining relationships as methods provides powerful method chaining and querying capabilities
What you mentioned about migrations is:
1.FOREIGN KEYS just ensure your data are consistent.
If we apply on delete cascade to the foreign key definition,referencing row will delete automatically when parent row will delete.
If we apply on Update Cascade to the foreign key definition,Child row will update automatically when parent row will update
This is not the same thing.
The hasOne(), hasMany(), belongsToOne() and belongsToMany() functions are merely query builders that return the results of a SQL query.
For example, the cars() method of the Person model with id is 1 in your example returns the results of the query SELECT * FROM cars WHERE person_id=1.
However, the foreign key has the same purpose than in a SQL script to create the cars table. For example:
CREATE TABLE cars (
...
person_id INT REFRENCES person(id),
...
);
I have a User-Tables aswell as an "Adress" Table. They can enter multiple Adresses to choose from when checking out.
Now I want to be able to have one adress set as the standard invoice adresse and another one as the standard invoise adress. I thought about doing it using a pivot table, containing the following:
Schema::create('users_adresses_pivot', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->integer('invoice_adress_id')->unsigned();
$table->foreign('invoice_adress_id')->references('id')->on('adresses');
$table->integer('delivery_adress_id')->unsigned();
$table->foreign('delivery_adress_id')->references('id')->on('adresses');
$table->timestamps();
});
However I'm not sure if thats the right way. It looks a bit like a bad practice to me. If I choose this option how do I set the Relations? Because I would need two Relations from User to Adresses. I already got one in order to foreach through them in a view. So If I replaced that with the Pivot Relation I could only get the standard invoice & delivery adresses instead of the others too. Any idea?
This is my current Relationship:
User.php:
public function adresses()
{
return $this->hasMany('App\Adress');
}
Adress.php:
public function user()
{
return $this->belongsTo('App\User');
}
IMHO dont use a pivot table, you dont need a many to many, this is a simple one to many relationship (one user has many addresses).
In the address table you just need to add two columns: "user_id" and "type".
The relations you wrote are good.
I thought that eloquent would (by default) enforce uniqueness accross the two id columns when generating a simple pivot (many-to-many) table?
Or am I doing something wrong?
Appointment model
public function client()
{
return $this->belongsToMany('App\Client')->withTimestamps();
}
Client model
public function appointment()
{
return $this->belongsToMany('App\Appointment')->withTimestamps();
}
Migration
$table->integer('appointment_id')->unsigned();
$table->foreign('appointment_id')->references('id')->on('appointments')->onDelete('cascade');
$table->integer('client_id')->unsigned();
$table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
$table->timestamps();
If eloquent doesn't do it by default, I'll have to add the index manually:
$table->unique(array('appointment_id', 'client_id'));
Eloquent can't enforce uniqueness accross the two id columns, because Eloquent is not responsible for the database schema/configuration.
Migrations are responsible for this stuff, so you have to define uniqueness in a migration.