When defining a one-to-one relationship between models in laravel, we will say :
class Model1 extends Model
{
public function model2()
{
return $this->hasOne('App\Model2');
}
}
and for Model2 we will use belongsTo('App\Model1') .
Is there a logic on how to decide on which end we will use each function?
The difference between the two is where the foreign key will reside in the database. The belongsTo function should belong to the model whose table contains the foreign key, while the hasOne should belong to a model that is referenced by a foreign key from another table.
Both will work, but you should maintain solid coding practices for other developers that may use your system in the future. Also, this becomes crucial if your foreign key cascades the delete. If you delete model1, should model2 that belongsTo model1 be deleted also?
Related
I have a table where I need to save the ids in array, you can see the items in
events_who is a foreign keys. Any solution where I can create a Relationship in my Model to get the data from the foreign keys? I tried belongsToMany and it doesn't work. :(
Any suggestions?
Let's assume we are having 2 models: Event and Person
And a Person can participate to multiple Event
Based on the mentioned relationships, you need to create a pivot table called event_person and define two belongsToMany() relationships in both models:
In the Person model, the relationship will look like:
public function events()
{
return $this->belongsToMany(Event::class, 'event_person');
}
Laravel / MySQL (Relational Database) don't really work this way. You should check out Many to Many Relationships in this case.
Example table schema/layout:
users
|id|name|password|
events
|id|title|body|
event_user (pivot table)
|event_id|user_id|
Usually there won't be an array in a column, you should use tables instead. Besides, normally a foreign key would be a table name(singular) following by _id.
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 have pivot table and it has one to many relationship with another table, So I am confused with database design and relationship in Laravel Elequent.
Is this right way to design databse or should I create id as primary key for award_entries and use it is foreign key in entry_files. ?
If I am following existing design (first one), how will I write relation in Laravel eloquent?
Here how your relation will look like. You may need to change model or columns name.
In award_entry model:
public function entry_file() {
return $this->belongsTo('App\Models\entry_file','award_entries_award_id');
}
And in Entry_file model:
public function award_entries(){
return $this->hasMany('App\Models\award_entries','award_entries_award_id');
}
I have a couple of models that I have included pivot tables for to avoid a polymorphic relation.
role table
id
name
description
restriction table
id
rule
status
restriction_role table
id
restriction_id
role_id
Reason for this setup is that both Roles and Restrictions can actually belong to multiple other models. In this case, a Role can only have 1 Restriction. I would normally define this as
class Role extends Eloquent {
public function restrictions()
{
return $this->hasOne('Restriction');
}
}
This obviously does not work because Laravel is unaware of the pivot table connecting this relation. I could easily accomplish this by using a many-to-many relationship instead, but this is not exactly how my model works. Not seeing anything in the documentation for defining this. Any thoughts?
I've solved this by using the belongsToMany relation and defining a custom accessor for it, like so:
public function foo()
{
return $this->belongsToMany(App\Bar::class);
}
public function getFooAttribute()
{
return $this->foo()->first();
}
As #deczo stated in the comments, belongsToMany() is about all that will work here. I recommend returning the first result using the first() method if you require only one result but cannot use a hasOne() relationship.