Laravel - 反向多态关系
Laravel - reverse polymorphic relationship
我基本上有两个模型(狗和猫)相同类型:宠物. table 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 │
└──────────────┘ └───────────┘ └───────────┘
宠物table:
┌────┬──────────────┬────────────┐
│ id │ related_type │ related_id │
├────┼──────────────┼────────────┤
│ 1 │ dog │ 1 │
├────┼──────────────┼────────────┤
│ 2 │ dog │ 2 │
├────┼──────────────┼────────────┤
│ 3 │ cat │ 1 │
└────┴──────────────┴────────────┘
我搜索了 Laravel 文档,但 none 的关系似乎适合这个问题。只有多态关系才能反过来工作,这样我就可以通过 dog- 或 cat-id 访问宠物模型。但我正在寻找一种相反的解决方案。有没有不需要在 PetController 中手动使用讨厌的 if-else 的关系?
谢谢!
您需要将模型命名空间保留在 pats table(related_type
列)中。添加到您的宠物模型
public function concretePet()
{
return $this->hasOne($this->related_type, 'id', 'related_id');
}
使用:
$pet = Pet::findOrFail($id)->concretePet;
你可以像这样定义这 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
您可以为此创建自己的特征:
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.
我基本上有两个模型(狗和猫)相同类型:宠物. table 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 │
└──────────────┘ └───────────┘ └───────────┘
宠物table:
┌────┬──────────────┬────────────┐
│ id │ related_type │ related_id │
├────┼──────────────┼────────────┤
│ 1 │ dog │ 1 │
├────┼──────────────┼────────────┤
│ 2 │ dog │ 2 │
├────┼──────────────┼────────────┤
│ 3 │ cat │ 1 │
└────┴──────────────┴────────────┘
我搜索了 Laravel 文档,但 none 的关系似乎适合这个问题。只有多态关系才能反过来工作,这样我就可以通过 dog- 或 cat-id 访问宠物模型。但我正在寻找一种相反的解决方案。有没有不需要在 PetController 中手动使用讨厌的 if-else 的关系?
谢谢!
您需要将模型命名空间保留在 pats table(related_type
列)中。添加到您的宠物模型
public function concretePet()
{
return $this->hasOne($this->related_type, 'id', 'related_id');
}
使用:
$pet = Pet::findOrFail($id)->concretePet;
你可以像这样定义这 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
您可以为此创建自己的特征:
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.