【问题标题】:Laravel - reverse polymorphic relationshipLaravel - 反向多态关系
【发布时间】:2018-12-20 13:52:11
【问题描述】:

我基本上有两个相同类型的模型(dogcat):petspets 表连接了数据库中的所有狗和猫。现在我希望能够通过 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?
  • 我正在寻找将猫或狗与宠物条目连接起来的任何类型的关系。由于它们的类型不同,我不能简单地使用外键。
  • 我理解你 =) 结果应该是什么?)

标签: php laravel eloquent relationship polymorphic-associations


【解决方案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

【讨论】:

  • 很好的答案!尽管对于这个特定的示例,morphOnemorphMany 更合适,因为一个狗/猫行应该只有一个对应的宠物行。
【解决方案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().'.*')”
猜你喜欢
  • 2017-02-25
  • 2016-08-18
  • 2013-08-12
  • 2011-09-19
  • 2019-01-07
  • 1970-01-01
  • 1970-01-01
  • 2020-07-31
  • 2015-08-25
相关资源
最近更新 更多