Laravel - 反向多态关系
Posted
技术标签:
【中文标题】Laravel - 反向多态关系【英文标题】:Laravel - reverse polymorphic relationship 【发布时间】:2018-12-20 13:52:11 【问题描述】:我基本上有两个相同类型的模型(dog 和 cat):pets。 pets 表连接了数据库中的所有狗和猫。现在我希望能够通过 PetController 中的宠物 id 找到特定的宠物。像这样:
$pet = Pet::findOrFail($id); // returns a dog or cat
表格结构:
┌──────────────┐ ┌───────────┐ ┌───────────┐
│ pets │ │ dogs │ │ cats │
├──────────────┤ ├───────────┤ ├───────────┤
│ id │ │ id │ │ id │
│ related_type │ │ name │ │ name │
│ related_id │ │ eye_color │ │ tail_size │
└──────────────┘ └───────────┘ └───────────┘
宠物桌:
┌────┬──────────────┬────────────┐
│ id │ related_type │ related_id │
├────┼──────────────┼────────────┤
│ 1 │ dog │ 1 │
├────┼──────────────┼────────────┤
│ 2 │ dog │ 2 │
├────┼──────────────┼────────────┤
│ 3 │ cat │ 1 │
└────┴──────────────┴────────────┘
我搜索了 Laravel 文档,但似乎没有一个关系适合这个问题。只有多态关系才能反过来工作,这样我就可以通过 dog-或 cat-id 访问宠物模型。但我正在寻找一种相反的解决方案。有什么关系不需要手动在 PetController 中使用讨厌的 if-else 吗?
谢谢!
【问题讨论】:
您需要查找具有 1 个 id 的狗和猫(例如)?? 不,即我想找到宠物 ID 为 3 的任何类型的宠物(返回 id 为 1 的猫) Pet::where('related_id', $id)->first(), no? 我正在寻找将猫或狗与宠物条目连接起来的任何类型的关系。由于它们的类型不同,我不能简单地使用外键。 我理解你 =) 结果应该是什么?) 【参考方案1】:您需要将模型命名空间保留在 pats 表中(related_type
列)。添加到您的 PetModel
public function concretePet()
return $this->hasOne($this->related_type, 'id', 'related_id');
用途:
$pet = Pet::findOrFail($id)->concretePet;
【讨论】:
谢谢,看起来很棒!我去看看! 不幸的是,由于$this->related_type
为空,因此这不适用于急切加载。【参考方案2】:
你可以像这样定义这3个模型之间的多态关系
宠物模型
public function related()
$this->morphTo();
狗模型
public function pets()
$this->morphMany('App\Pet', 'related');
猫模型
public function pets()
$this->morphMany('App\Pet', 'related');
现在像这样获取它
$pet = Pet::findOrFail($id)->related;
dd($pet); //you will get either cat or dog
轻松创建
$dog = Dog::create(['name'=> 'dog1', 'eye_color' => 'gray']);
$dog->pets()->create();
在此处查看详细信息https://laravel.com/docs/5.6/eloquent-relationships#polymorphic-relations
【讨论】:
很好的答案!尽管对于这个特定的示例,morphOne
比 morphMany
更合适,因为一个狗/猫行应该只有一个对应的宠物行。【参考方案3】:
您可以为此创建自己的特征:
app/MorphToModel.php
<?php
namespace App;
trait MorphToModel
protected function morphToModel($related, $name = 'related', $foreignKey = 'id')
$table = $this->getTable();
return $this->belongsTo($related, $name . '_id', $foreignKey)
->join(
$table,
$table . '.' . $name . '_id',
($model = new $related)->getTable() . '.' . $model->getKeyName()
)->where($table . '.' . $name . '_type', $related);
在你的模型中使用特征:
app/Pet.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Pet extends Model
use MorphToModel;
// ...
public function related()
return $this->morphTo();
public function cat()
return $this->morphToModel(Cat::class);
public function dog()
return $this->morphToModel(Dog::class);
用法:
$pet = Pet::findOrFail($id);
$pet->cat; // A cat model or null.
$pet->dog; // A dog model or null.
$pet->cat() // A cat relationship query builder.
$pet->dog() // A dog relationship query builder.
【讨论】:
还有一点是添加“->select($model->getTable().'.*')”以上是关于Laravel - 反向多态关系的主要内容,如果未能解决你的问题,请参考以下文章