I'm actually confused about using either hasOne() or belongsTo() relationship. Assuming the relation is 1:1. Then which one?
An invoice hasOne a customer?
An invoice belongsTo a customer?
Noted that I've implemented both, and they works well .. But what's the standard one? When should I use which one?
hasOne can be used in a strong model or entity
belongsTo can be used in a weak model or entity.
I am sure you have an idea of strong and weak entities in database.
you can use invice hasOne(customer) in your case you can not use hasOne() with customer because customer has many invoices so batter use hasOne() with invoice and belongsTo() with customer.
Ex. invoice model
hasOne(customer)
while in customer model
belongsTo(invoice)
It depends on which table has the foreign key.
Imagine a relationship between Person and car.
The Owner can own one Car.
The Car can be owned by one Owner.
So, the Owner hasOne Car, and the car belongsTo an Ownwe. So, the foreign key will go in "car". The car needs to know who it belongsTo.
In your case, the invoice needs to know who it belongs to, so, if a customer can have many invoices, customer hasMany(Invoice::class) and invoices belongsTo(Customer::class).
If your 2 related tables/entities have a relationship as one-to-one they should be defined using hasOne.
If your 2 related tables/entities have a relationship as one-to-many like A has many B, then A should define B as hasMany and B should define A as belongsTo which will be called as One To Many (Inverse)
For your case both models could define each other as hasOne and inverse side of model should define owning model as belongsTo
An invoice hasOne customer , customer belongsTo invoice
A customer hasOne invoice, invoice belongsTo customer
In a one-to-one relationship the table/entity holding the foreign key of the related table/entity is always the owning side of the relation and other will be inverse side of relation.
Related
All I'm trying to do is understanding when exactly should I use hasOne() and when should I use belongsTo(). Both seem identical to me. For example, here is my model:
use Illuminate\Database\Eloquent\Model;
use App\Categories;
use App\User;
class tickets extends Model
{
protected $table = "tickets";
public function category()
{
return $this->hasOne(Categories::class, 'id', 'category_id');
}
public function user()
{
return $this->hasOne(User::class, 'id', 'user_id');
}
}
I can do the same by using belongsTo() function too. Just I should put them into user and category models instead. Anyway, when should I use either hasOne() or belongsTo() ?
When dealing with 1 to many relationships, you will have a hasMany()and a belongsTo() .
The rule of thumb I use, is if a table has a foreign key (tickets table has a user_id fk) then this model belongsTo users.
The same with Category.
So your above example, Ticket belongsTo User & Category.
Inversely, User hasMany Ticket and similarly Category hasMany Ticket
Anyway, when should I use either hasOne() or belongsTo() ?
Think of it like what would be hasMany if there is one to many relation probable in the future. For example: consider User and Phone models. Nature of relation would be User hasOne Phone, but if you would like to extend functionality for it so user could have multiple phone numbers registered User would still have has* relation while Phone would keep belongsTo relation. Just consider which one could be "parent" entity and that one should have hasOne relation in method. I would always consider User as parent entity and for me logically would be user has one ticket.
Also, try to stick with Eloquent/Laravel/artisan naming convention and name that model Ticket and other one Category (Eloquent and Laravel will solve plural where needed i.e. table name).
hasOne is a 1:1, or one-to-one relationship.
hasMany is a 1:n, or one-to-many relationship.
The belongsTo method in Eloquent is used to define the inverse of these relationships.
The definition of these will depend on your data model.
In your case:
You have a Category model, which hasMany Tickets.
You also have a User model, which hasMany Tickets.
Now from the Ticket perspective, you would want to define the inverses of these 2 hasMany relationships. You will do this by defining a belongsTo.
So the Ticket belongsTo a User and belongsTo a Category.
To answer your question:
From the Tickets perspective, it is a 1:1 relation, because the foreign key in the Ticket model points to 1 User and the category foreign key points to 1 Category.
But since the relation you created is a 1:n (one-to-many) and you have also defined it on the User and Category models, you should define the relation in your Ticket model as the inverse of those relations, and the inverse of a hasMany (and hasOne) is belongsTo.
When defining your relations in Laravel, keep your database schema in mind and define your relations in the same way that they exist in your database schema.
These are same with a single difference. Both returns the single associated object with one difference. When we declare some relation as belongsTo it means there is a database table which has a foreign key of some other table. When we declare hasOne relation it means that this table's primary key has been referenced in another table. Think of it as a parent child table. When we would make the child table we reference each child to its parent, right? This is belongsTo. And when we would make the parent table we know that each entry in parents table can have a single or many entries in the child table. That's hasOne or hasMany relation. You can ask further if you need any more clarification.
In my application, a model Device has a many-to-many relationship with model Task.
A combination of Device and Task could be assigned to a various number of model User.
example: Device A has a Task Check something and this should be done by User Frank and Steven.
From my point of view, this should be a "standard problem", but so far I could not find a proper solution.
Right now, I use following workaround:
a) added an unique ID id to the device_task pivot table
b) query id from the pivot table
c) create a new table device_task_user which contains user_id and device_task_id
b) use query builder to get/add users
But I am really not happy with this approche.
Would it be possible, that the pivot table also extends Model and then have a one-to-many relationship with User?
Or would you suggest to add a json colum to the pivot table and store the users there?
Any idea would be very welcome!
Would it be possible, that the pivot table also extends Model
Yes, it's possible. From the docs:
If you would like to define a custom model to represent the intermediate table of your relationship, you may call the using method when defining the relationship. All custom models used to represent intermediate tables of relationships must extend the Illuminate\Database\Eloquent\Relations\Pivot class
You also can create a new hasMany() and belongsTo() relationships between Task and Device models and use them as well as existing belongsToMany relationship. And you'll need to define a new relationship between pivot model and User model to be able to get data by device, task or user.
Modify many-to-many relationship to hold an extra field user_id
class Device extends Model
{
public function tasks()
{
return $this->belongsToMany(
Task::class,
'device_task',
'device_id',
'task_id'
)->withPivot('user_id');
}
}
And when updating do like this in controller
$device->tasks()->attach([$taskId]=>['user_id']=>$userId);
And of-course you need DeviceTask model and also a has-many relationship between User model and DeviceTask model to get user's task
I'm curious why the Eloquent relationship for hasMany has a different signature than for belongsToMany. Specifically the custom join table name-- for a system where a given Comment belongs to many Roles, and a given Role would have many Comments, I want to store the relationship in a table called my_custom_join_table and have the keys set up as comment_key and role_key.
return $this->belongsToMany('App\Role', 'my_custom_join_table', 'comment_key', 'role_key'); // works
But on the inverse, I can't define that custom table (at least the docs don't mention it):
return $this->hasMany('App\Comment', 'comment_key', 'role_key');
If I have a Role object that hasMany Comments, but I use a non-standard table name to store that relationship, why can I use this non-standard table going one way but not the other?
hasMany is used in a One To Many relationship while belongsToMany refers to a Many To Many relationship. They are both distinct relationship types and each require a different database structure - thus they take different parameters.
The key difference is that in a One To Many relationship, you only need the two database tables that correspond to the related models. This is because the reference to the relation is stored on the owned model's table itself. For instance, you might have a Country model and a City model. A Country has many cities. However, each City only exists in one country. Therefore, you would store that country on the City model itself (as country_id or something like that).
However, a Many To Many relationship requires a third database table, called a pivot table. The pivot table stores references to both the models and you can declare it as a second parameter in the relationship declaration. For example, imagine you have your City model and you also have a Car model. You want a relationship to show the types of cars people drive in each city. Well, in one city people will drive many different types of car. However, if you look at one car type you will also know that it can be driven in many different cities. Therefore it would be impossible to store a city_id or a car_id on either model because each would have more than one. Therefore, you put those references in the pivot table.
As a rule of thumb, if you use a belongsToMany relationship, it can only be paired with another belongsToMany relationship and means that you have a third pivot table. If you use a hasMany relationship, it can only be paired with a belongsTo relationship and no extra database tables are required.
In your example, you just need to make the inverse relation into a belongsToMany and add your custom table again, along with the foreign and local keys (reversing the order from the other model).
Try to understand with text and a figure.
One to One(hasOne) relationship:
A user has(can have) one profile. So, a profile belongs to one user.
One to many(hasMany):
A user has many(can have many) articles. So, many articles belong to one user.
Many to many(BelongsToMany):
A User can belong to many forums. So, a forum belongs to many users.
I have a model Status which have a name attribute.
Further I have two (later maybe n) other Models which can have a Status assigned by a belongsTo() relationship.
Now I want to have constraints that model A could only have specific statuses and model B other specific statuses.
My problem is that I don´t know which would be a good design to enforce these constraints.
Of course I could have different models for statuses for A and B but I already have the status table and model B was added later.
I thought maybe I could add a model AStatus and BStatus and so on, which would have a foreign key to a Status, but then I don´t know how I would express this relationship in Laravel Eloquent.
Another option would be to add a attribute to the existing Status table which indicates which Model is allowed to have this status. But this doesn't feels like a good idea, because then I could not express that multiple Models could have the same status.
I hope you can help me!
Say I have models User and Post
Clearly, User hasMany Post
But now I want to have subscriptions.
Do I create a second relationship user/post relationship that is HABTM in addition to the relationship they already have?
I think that you need to create the relation User belongsTo Subscriptions.
I do not see that having a relationship HABTM
You could do this with two different hasMany associations, a new belongsTo association, or a new HABTM association. It really depends on how you want to organize and access your data.
To answer the question you posed in the comments, yes, it's possible to have multiple relationships between the same set of Models. Please read: Multiple relations to the same model from the Cake book.
Of course you can add more than one relation on the same model. You han have: User hasMany Post
User hasMany Subscription
Post belongsTo User
Subscription belongsTo User
On both direction you can get all users's posts and posts that belong to users.