Laravel:多对多共享 table
Laravel: many-to-many with shared table
我有 Locations
个模型,其中有许多 Employees
-- 同样 Employees
属于 Locations
这很好,效果很好,但后来我考虑添加 PhoneNumbers
。 一个 Location
或一个 Employee
可能有一个 phone 号码(办公室号码与个人号码)
逻辑上:
Locations
hasMany PhoneNumbers
(多条线路)
和
Employees
hasMany PhoneNumbers
(家/小区?)
然而,当您在 Laravel 中创建这样的 hasMany 关系时,它会向 PhoneNumbers
table 添加一个字段。所以我们现在有 两个 字段:location_id
和 employee_id
如果我让 location_id
和 employee_id
可以为空,我就可以让它工作,就像这样:
+----+--------------+-------------+-------------+
| 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 |
...
然而,如果我添加可以拥有 phone 个数字的新实体(客户?求职者?供应商?)
如何使用同一个辅助 table 创建多个单独的多对多关系?
注意: 在这个例子中,我可以在每个 table 上创建一个 phone_number
字段(locations.phone_number
,employees.phone_number
, 等)但是我希望避免这种情况有两个原因:
- 数据完整性(如果所有 phone 号码都在一个公共 table 中,则很容易验证是否输入了重复的 phone 号码)
- 绑定到更复杂的模型(将
PhoneNumber
替换为 Image
,现在您有更多的数据要处理)
您正在寻找 Laravel 的多态关系。您没有为每个相关 table 创建一个新字段,而是有两个字段:相关 ID 和相关类型。
在您的 Location 和 Employee 模型中,添加以下关系:
public function phones()
{
return $this->morphMany('PhoneNumber', 'phonable');
}
在您的 PhoneNumber 模型上,添加以下关系:
public function phonable()
{
return $this->morphTo();
}
在您的 phone_numbers table 上,添加两个新字段:phonable_type 和 phonable_id。在迁移中,这些字段使用 morphs()
方法添加:$table->morphs('phonable');
一切设置完成后,您的数据将如下所示:
+----+--------------+-------------+---------------+
| 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 |
...
使用此设置,您可以创建任何您想要的模型 phonable
,只需向其添加 morphOne()
或 morphMany()
关系即可。
此外,关系属性将生成与类型相关的正确模型。给定以上数据:
var_dump(PhoneNumber::find(1)->phonable); // will dump Location object
var_dump(PhoneNumber::find(4)->phonable); // will dump Employee object
可以找到关于多态关系的文档 here (4.2) or here (5.0)。
我有 Locations
个模型,其中有许多 Employees
-- 同样 Employees
属于 Locations
这很好,效果很好,但后来我考虑添加 PhoneNumbers
。 一个 Location
或一个 Employee
可能有一个 phone 号码(办公室号码与个人号码)
逻辑上:
Locations
hasMany PhoneNumbers
(多条线路)
和
Employees
hasMany PhoneNumbers
(家/小区?)
然而,当您在 Laravel 中创建这样的 hasMany 关系时,它会向 PhoneNumbers
table 添加一个字段。所以我们现在有 两个 字段:location_id
和 employee_id
如果我让 location_id
和 employee_id
可以为空,我就可以让它工作,就像这样:
+----+--------------+-------------+-------------+
| 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 |
...
然而,如果我添加可以拥有 phone 个数字的新实体(客户?求职者?供应商?)
如何使用同一个辅助 table 创建多个单独的多对多关系?
注意: 在这个例子中,我可以在每个 table 上创建一个 phone_number
字段(locations.phone_number
,employees.phone_number
, 等)但是我希望避免这种情况有两个原因:
- 数据完整性(如果所有 phone 号码都在一个公共 table 中,则很容易验证是否输入了重复的 phone 号码)
- 绑定到更复杂的模型(将
PhoneNumber
替换为Image
,现在您有更多的数据要处理)
您正在寻找 Laravel 的多态关系。您没有为每个相关 table 创建一个新字段,而是有两个字段:相关 ID 和相关类型。
在您的 Location 和 Employee 模型中,添加以下关系:
public function phones()
{
return $this->morphMany('PhoneNumber', 'phonable');
}
在您的 PhoneNumber 模型上,添加以下关系:
public function phonable()
{
return $this->morphTo();
}
在您的 phone_numbers table 上,添加两个新字段:phonable_type 和 phonable_id。在迁移中,这些字段使用 morphs()
方法添加:$table->morphs('phonable');
一切设置完成后,您的数据将如下所示:
+----+--------------+-------------+---------------+
| 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 |
...
使用此设置,您可以创建任何您想要的模型 phonable
,只需向其添加 morphOne()
或 morphMany()
关系即可。
此外,关系属性将生成与类型相关的正确模型。给定以上数据:
var_dump(PhoneNumber::find(1)->phonable); // will dump Location object
var_dump(PhoneNumber::find(4)->phonable); // will dump Employee object
可以找到关于多态关系的文档 here (4.2) or here (5.0)。