【问题标题】:How to set Eloquent relationship belongsTo THROUGH another model in Laravel?如何通过 Laravel 中的另一个模型设置 Eloquent 关系属于到?
【发布时间】:2014-12-07 07:23:49
【问题描述】:

我有一个模型Listing,通过它的belongsTo('Model') 关系继承应该固有地属于其对应模型所属的制造商。

这是我的清单模型:

    public function model()
    {
        return $this->belongsTo('Model', 'model_id');
    }

    public function manufacturer()
    {
        return $this->belongsTo('Manufacturer', 'models.manufacturer_id');
        /*
        $manufacturer_id = $this->model->manufacturer_id;
        return Manufacturer::find($manufacturer_id)->name;*/
    }

和我的制造商型号:

public function listings()
{
    return $this->hasManyThrough('Listing', 'Model', 'manufacturer_id', 'model_id');
}

public function models()
{
    return $this->hasMany('Model', 'manufacturer_id');
}

我可以在视图中回显 $listing->model->name,但不能回显 $listing->manufacturer->name。这会引发错误。我尝试了列表模型中注释掉的 2 行,只是为了获得效果,这样我就可以回显 $listing->manufacturer() 并且这会起作用,但这并不能正确地建立它们的关系。我该怎么做呢?谢谢。

修改列表模型(感谢回答者):

    public function model()
    {
        return $this->belongsTo('Model', 'model_id');
    }

    public function manufacturer()
    {
        return $this->belongsTo('Model', 'model_id')
            ->join('manufacturers', 'manufacturers.id', '=', 'models.manufacturer_id');
    }

【问题讨论】:

    标签: php laravel eloquent


    【解决方案1】:

    你可以这样做(学生组 -> 用户 -> 投票结果):

    // poll result
    
        public function studentGroup(): HasOneDeep
        {
            return $this->hasOneDeepFromRelations($this->user(), (new User())->studentGroup());
        }
    

    【讨论】:

    • 调用未定义的方法i::hasOneDeepFromRelations()
    【解决方案2】:

    我想这可能会有所帮助,它帮助了我:

    class Car extends Model
    {
        public function mechanical()
        {
            return $this->belongsTo(Mechanical::class);
        }
    }
    
    class CarPiece extends Model
    {
        public function car()
        {
            return $this->belongsTo(Car::class);
        }
    
        public function mechanical()
        {
            return $this->car->mechanical();
        }
    }
    

    至少,正是这种需要让我想到了belongsToThrough的存在

    【讨论】:

    • 欢迎来到 Stack Overflow。在 Stack Overflow 上不鼓励仅使用代码的答案,因为它们没有解释它是如何解决问题的。请编辑您的答案以解释此代码的作用以及它如何回答问题,以便对其他有类似问题的用户有用。
    • 我尝试过类似的方法,但它有一些问题。首先,CarPiece 上的mechanical 无法立即加载,因为尚未加载car。这不是什么大问题,但在使用作业时是个问题,因为出于某种原因,作业坚持在反序列化时急切加载所有内容:(
    【解决方案3】:

    我找到了一个解决方案,但它并不是非常简单。我已经在下面发布了,但我先发布了我认为更好的解决方案。

    您不能直接从列表中访问制造商,因为制造商仅适用于模型。尽管您可以从列表对象中预先加载制造商关系,但请参见下文。

    class Listing extends Eloquent
    {
        public function model()
        {
            return $this->belongsTo('Model', 'model_id');
        }
    }
    
    class Model extends Eloquent
    {
        public function manufacturer()
        {
            return $this->belongsTo('manufacturer');
        }
    }
    
    class Manufacturer extends Eloquent
    {
    } 
    
    $listings = Listing::with('model.manufacturer')->all();
    foreach($listings as $listing) {
        echo $listing->model->name . ' by ' . $listing->model->manufacturer->name;
    }
    

    为了让您请求的解决方案发挥作用,我们费了一番周折。解决方案如下所示:

    public function manufacturer()
    {
        $instance = new Manufacturer();
        $instance->setTable('models');
        $query = $instance->newQuery();
    
        return (new BelongsTo($query, $this, 'model_id', $instance->getKeyName(), 'manufacturer'))
            ->join('manufacturers', 'manufacturers.id', '=', 'models.manufacturer_id')
            ->select(DB::raw('manufacturers.*'));
    }
    

    我首先处理查询并从中构建响应。我想要创建的查询类似于:

    SELECT * FROM manufacturers ma
        JOIN models m on m.manufacturer_id = ma.id
    WHERE m.id in (?)
    

    通常通过return $this->belongsTo('Manufacturer');创建的查询

    select * from `manufacturers` where `manufacturers`.`id` in (?)
    

    ? 将替换为列表表中manufacturer_id 列的值。此列不存在,因此将插入一个 0 并且您永远不会返回制造商。

    在我想重新创建的查询中,我受到models.id 的约束。我可以通过定义外键轻松访问我的关系中的该值。于是关系就变成了

    return $this->belongsTo('Manufacturer', 'model_id');
    

    这会产生与之前相同的查询,但会使用 model_ids 填充 ?。所以这会返回结果,但通常是不正确的结果。然后我的目标是更改我从中选择的基表。这个值是模型派生出来的,所以我把传入的模型改成Model

    return $this->belongsTo('Model', 'model_id');
    

    我们现在已经模仿了模型关系,所以这很好,我还没有真正做到。但至少现在,我可以加入制造商表。所以我再次更新了关系:

    return $this->belongsTo('Model', 'model_id')
        ->join('manufacturers', 'manufacturers.id', '=', 'models.manufacturer_id');
    

    这让我们更进一步,生成以下查询:

    select * from `models` 
        inner join `manufacturers` on `manufacturers`.`id` = `models`.`manufacturer_id`
        where `models`.`id` in (?)
    

    从这里开始,我想将查询的列限制为制造商列,为此我添加了选择规范。这将关系带到:

    return $this->belongsTo('Model', 'model_id') ->join('manufacturers', 'manufacturers.id', '=', 'models.manufacturer_id') ->select(DB::raw('manufacturers.*'));

    得到查询

    select manufacturers.* from `models` 
        inner join `manufacturers` on `manufacturers`.`id` = `models`.`manufacturer_id`
        where `models`.`id` in (?)
    

    现在我们有一个 100% 有效的查询,但是从关系返回的对象是 Model 类型而不是 Manufacturer。这就是最后一点诡计的来源。我需要返回一个Manufacturer, but wanted it to constrain by themodelstable in the where clause. I created a new instance of Manufacturer and set the table tomodels` 并手动创建关系。

    请务必注意,保存无效

    $listing = Listing::find(1);
    $listing->manufacturer()->associate(Manufacturer::create([]));
    $listing->save();
    

    这将创建一个新的制造商,然后将listings.model_id 更新为新制造商的 ID。

    【讨论】:

    • 非常感谢!我无法要求更彻底的解释。无论如何都不应该将制造商直接分配到列表中,因此节省不是问题;我通过模型关联了制造商,因此只分配了模型(在UI中,选择制造商,然后显示其模型,选择模型,将通过模型保存间接分配制造商)。
    • 我正在使用您提供的后一种解决方案,但更紧凑...您能解释一下使用您的第一个解决方案有什么好处吗?
    猜你喜欢
    • 2014-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-26
    • 2020-03-04
    • 2013-11-17
    • 2016-05-10
    相关资源
    最近更新 更多