Laravel - Database relationships - laravel

Let's consider a simple scenario of 'Company' and 'Employee' models.
A company has many employees. Now, when I map this relationship in Laravel, what is the correct approach from the following?
Approach 1:
Employee belongsTo() Company and Company hasMany() Employee
Approach 2:
Company belongsToMany() Employee and Employee hasOne() Company
Basically, what is the difference between belongsTo()-hasMany() and belongsToMany()-hasOne()?

There are three different approaches, in your question you're mixing them up a little. I'll go through all of them.
Many-to-many
A many-to-many relationship would mean, in your example, that a company can have multiple employees and that an employee can work for multiple companies.
So when you're using the belongsToMany() method on a relation, that implies you have a pivot table. Laravel by default assumes that this table is named after both other tables, e.g. company_employee in the example. Both the Company model and the Employee model would then have belongsToMany() relations.
Many-to-one
However, using hasMany() means that it's a one-to-many relationship. If we look at the example again, a company might have many employees but each employee would only be able to be employed by one company.
In the models, that means the Company would have a hasMany() method in its relationship declaration, while the Employee would have a belongsTo() method.
One-to-one
Finally, hasOne() means that it's a one-to-one relationship. What it would mean in your example is that each company may only have one employee. Since the inverse of hasOne() is also belongsTo(), in this scenario, too, every employee could be employed by only one company.
The Company model would then have a hasOne() relationship method, with the Employee having a belongsTo() method.
In practice, you almost always want to construct a database that is as close to reality in its representation as possible. What relationships you use depends on what your case looks like. In the example, I would guess that you want a many-to-one approach, with a foreign key on the employees table, that references the id on the companies table. But ultimately, that's up to you. Hope that helped. :)

Related

Creating a relationship from Pivot Table Field

I cannot find a solution, likely to how I am phrasing the question. I have a model called Invoice and it has the following relationship:
public function manifests(){
return $this->morphedByMany(carrier_manifest::class, 'invoiceable')->withPivot(['amount','rate_id','notes']);
}
As you can see, in the pivot, I have a table called rate_id. I would like to be able to add a relationship to another model based on the value of the rate_id (the model just being called ChargeRates). Is there a way I can do this in order to access a field in the ChargeRates model called label?
You'd want to actually implement the pivot table as a model if it has relationships and functionality on its own.
From a database concern, a many to many relationship between Table A and Table B is really just a one-to-many relationship between Table A and the pivot table and a one-to-many relationship between Table B and the pivot table.
Therefore, implementing your relationships with a pivot model using hasMany or morphMany is a way for you to accomplish what you're after.

Can Laravel hasOne be used with belongsToMany?

Let's say I have two tables:
Users: id, name, country_id
Countries: id, name
Of course each user can only have one country, but each country is assigned to multiple users.
So would it be safe to have a User model that utilizes hasOne and a Country model that uses belongsToMany method?
Documentation makes it seem like you can't mix and match different types of relationships.
What you are describing is actually a One To Many relationship, where one country has many users. Your Country model should utilize a hasMany relationship, while your user would have a belongsTo relationship.
#Andy has already answered well.
Anyway, my advice is to always think in the following way to create a One-To-One, One-To-Many, or a Many-To-Many relationship:
In the table with the foreign key (if any) use belongsTo
In the other table without the foreign key use hasOne or hasMany
In any of them have a foreign key, you have a Many To Many relationship and you must use belongsToMany in both of them (you need the pivot table, of course).

Laravel - Eloquent Models Relations, polymorphic or not?

I have this schema
All the relations here must be one-to-zero/one.
A user can be either an employee or a customer. The user_type ENUM gives me the type so I know where to go from there.
Then an employee can be either basic or a manager. The employee_type discriminator let's me know that.
How am I supposed to build the Eloquent Model relations?
Let's say I have a user that is an employee. I need to get it's common fields from the users table but also need to get common fields from employees table. Do I need to hard code, and know that when user_type=emp I need to select from the employees table? What if I need to add another user type later?
UPDATE
Would it make sense to change my schema into something simpler?
My problem is that by using, as suggested, polymorphic relations I would end up to something like this:
$user = new User::userable()->employable()->...
Would a schema in which I drop the employees table and have employee_managers and employee_basics linked straight to the users table?
this is an polymorphic relationship. but if you want to be easy, you need to fix some things.
in the table employees
- user_id
- employable_id
- employable_type enum(Manager, Basic) # References to the target model
.... this last two are for the polymorphic relation, this is the nomenclature
in the basics and managers table you could delete the user_id field, but you need an id field as increments type
and now in the model Employee you need to make this function
public function employable(){
return $this->morphTo();
}
I hope this works :)

Eloquent hasManyThroughOne

Laravel 4.1 introduced the hasManyThrough relationship. This assumes 2 relating hasMany relationships. I however would like to retrieve the hasMany relationships of a belongsTo relationship instead.
Project (id, contact_id, ...)
Contact (id, ...)
Address (id, contact_id, ...)
For each project, I would like to get all addresses.
I managed to do this using a belongsTo() relationship and some additional table joining. However, a belongsTo relationship binds a single object, instead of an array.
So my thoughts are I either need to:
... be able to override the LIMIT 1 behavior on belongsTo relationships
... or be able to override the hasManyThrough to work with a belongsTo as intermediate relationship.
It sounds like you are trying to set up a many-to-many relationship between Projects and Contacts, with a one-to-one relationship between Address and Contact. If that is the case you will need to create a pivot table "project_contact" with columns "project_id" and "contact_id" as well as any other columns (timestamps(), etc). Then you can set a "belongsToMany('Project')" relationship on the Contacts.
I'm not sure if that is what you're after, but it solves the problem as I understand it.

Multiple relationships on a table

SQL Server 2012 MVC3 EF4.3.1 Code First project.
I have a Teacher and Student table with a one to many relationship. The Teacher’s tables Id will be used as the account number so its Id numbering needs to be separate from the Student’s. I would like to create a Person table (containing shared properties such as First, Last, Phone, Email) to reduce redundancy on the properties. Person will also have a one to many relationship to an Address table.
I’ve thought of trying a Table per Hierarchy model with Teacher and Student inheriting from Person but then the Id sets would not be separate and I would have to have a one to many relationship internally on the Person table. I could generate the ID’s through code but is an internal one to many doable or practical?
Another scenario would be to setup Person as a child table with a one to one between and Teacher and Person and a one to one between Student and Person but I’m not sure how or if it’s possible to have two separate one to one’s on a table.
Is there a practical way to do what I want or should I not worry about the redundancy and not use a Person table? If I went that route would it be possible to have two separate one to many relationships to an Address table (Teacher-Address and Student-Address)? Or for that matter a one to many (Teacher-Address, teacher may have an additional shipping address) and one to one (Student-Address)?
Thank you
Another way to do it is to have a one to one between a Person and a Role table. Teacher and Student are merely roles in this arrangement. A given Role can be fulfilled by many Person instances.
You could also do a Person table with an IsTeacher flag.
I can see two possibilities:
One: Go with your Student and Teacher inheriting from a base table of Person and not worry about the 'redundancy'. It's not a redundancy because your relating a Student and a Teacher not a Person to a Person and so in your database and DOM the Person table and Person class know nothing of the Teacher to Student relationship, it only knows that its a person. The teacher and student relationships are stored in there respective types, not the person type. Also, look at Table per Type instead of Table per Heiarchy. It's much cleaner and crisper looking in the database and you don't get all the information of each type in the heiarchy in one table.
Two: Create a table that specifically holds information that both Students and Teachers share and have that related to both the Student and Teacher table separately. You could call it something like "ContactInformation".
Being a teacher and being a student are roles of people, not types of people.
You should have a table for People, a table TeachCourse to say that a Person is the teacher of a course (which in some cases are multiple teachers), a table AssistCourse to say which persons are attending a class as a student. You might have people that teach a course and assist another course, and that wasn't properly modeled in your first version.
You can also create a ContactInformation or ShippingInformation table for People to specify all their data (Some people may have multiple phones, or emails to).

Resources