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_idemployee_id

如果我让 location_idemployee_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_numberemployees.phone_number, 等)但是我希望避免这种情况有两个原因:

  1. 数据完整性(如果所有 phone 号码都在一个公共 table 中,则很容易验证是否输入了重复的 phone 号码)
  2. 绑定到更复杂的模型(将 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)