我基本上有两个相同类型的模型( dog 和 cat ):宠物。表 pets 将数据库中的所有猫狗联接起来。现在,我希望能够通过PetController中的pet 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访问pet模型。但是我正在寻找一种可以反其道而行之的解决方案。有没有需要在PetController中手动使用讨厌的if-else的关系?
谢谢!
答案 0 :(得分:2)
您可以为此创建自己的特征:
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.
答案 1 :(得分:1)
您需要将模型namepase保留在pats表(related_type
列)中。添加到您的PetModel
public function concretePet()
{
return $this->hasOne($this->related_type, 'id', 'related_id');
}
使用:
$pet = Pet::findOrFail($id)->concretePet;
答案 2 :(得分:1)
您可以在这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
查看详细信息