问题
I have Locations model which hasMany Employees -- similarly Employees belongsTo Locations
This is nice and works well, but then I looked at adding PhoneNumbers. Either a Location or an Employee could have a phone number (office numbers versus personal numbers)
Logically:
Locations hasMany PhoneNumbers (multiple office lines)
and
Employees hasMany PhoneNumbers (home / cell ?)
However when you create a hasMany relationship like this in Laravel it adds a field to the PhoneNumbers table. So we now have two fields: location_id and employee_id
I can get this to work if I make location_id and employee_id nullable, like so:
+----+--------------+-------------+-------------+
| id | number | location_id | employee_id |
+----+--------------+-------------+-------------+
| 1 | 800-555-0123 | 1 | null |
| 2 | 800-555-0124 | 1 | null |
| 3 | 800-555-0125 | 1 | null |
| 4 | 859-555-0199 | null | 1 |
...
However this doesn't scale very well if I add new entities that can possess phone numbers (customers? job applicants? suppliers?)
How can I create multiple separate many-to-many relationships with the same secondary table?
Note: In this example I could just create a phone_number field on each individual tables (locations.phone_number, employees.phone_number, etc) however I wish to avoid this for two reasons:
- Data integrity (if all phone numbers are in one common table it's easy to verify duplicate phone numbers are not entered)
- Binding to more complex models (replace
PhoneNumberwithImageand now you have a lot more data to deal with)
回答1:
You're looking for Laravel's polymorphic relationship. Instead of creating a new field for each related table, you have two fields: related id and related type.
On both your Location and Employee model, add the following relationship:
public function phones()
{
return $this->morphMany('PhoneNumber', 'phonable');
}
On your PhoneNumber model, add the following relationship:
public function phonable()
{
return $this->morphTo();
}
On your phone_numbers table, add two new fields: phonable_type and phonable_id. In a migration, these fields are added with the morphs() method: $table->morphs('phonable');
Once everything is setup, your data would look like this:
+----+--------------+-------------+---------------+
| id | number | phonable_id | phonable_type |
+----+--------------+-------------+---------------+
| 1 | 800-555-0123 | 1 | Location |
| 2 | 800-555-0124 | 1 | Location |
| 3 | 800-555-0125 | 1 | Location |
| 4 | 859-555-0199 | 1 | Employee |
...
With this setup, you can make any model you want phonable just by adding a morphOne() or morphMany() relationship to it.
Additionally, the relationship attributes will generate the correct model related to the type. Given the data above:
var_dump(PhoneNumber::find(1)->phonable); // will dump Location object
var_dump(PhoneNumber::find(4)->phonable); // will dump Employee object
The documentation on polymorphic relationships can be found here (4.2) or here (5.0).
来源:https://stackoverflow.com/questions/28923610/laravel-many-to-many-with-shared-table