php 如何在 Laravel 中设置 Eloquent 关系属于通过另一个模型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26327965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 18:17:12  来源:igfitidea点击:

How to set Eloquent relationship belongsTo THROUGH another model in Laravel?

phplaraveleloquent

提问by user163831

I have a model Listing that inherits through its belongsTo('Model') relationship should inherently belong to the Manufacturer that its corresponding Model belongs to.

我有一个模型列表,它通过它的belongsTo('Model') 关系继承应该本质上属于其对应模型所属的制造商。

Here's from my Listing 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;*/
    }

and my Manufacturer model:

和我的制造商模型:

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

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

I am able to echo $listing->model->name in a view, but not $listing->manufacturer->name. That throws an error. I tried the commented out 2 lines in the Listing model just to get the effect so then I could echo $listing->manufacturer() and that would work, but that doesn't properly establish their relationship. How do I do this? Thanks.

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

Revised Listing model (thanks to answerer):

修订上市模型(感谢回答者):

    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');
    }

回答by Logan Bailey

I found a solution, but it's not extremely straight forward. I've posted it below, but I posted what I think is the better solution first.

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

You shouldn't be able to access manufacturer directly from the listing, since manufacturer applies to the Model only. Though you can eager-load the manufacturer relationships from the listing object, see below.

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

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;
}

It took a bit of finagling, to get your requested solution working. The solution looks like this:

为了使您要求的解决方案起作用,需要花费一些时间。解决方案如下所示:

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.*'));
}

I started off by working with the query and building the response from that. The query I was looking to create was something along the lines of:

我首先处理查询并从中构建响应。我想要创建的查询是这样的:

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

The query that would be normally created by doing return $this->belongsTo('Manufacturer');

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

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

The ?would be replaced by the value of manufacturer_idcolumns from the listings table. This column doesn't exist, so a single 0 would be inserted and you'd never return a manufacturer.

?会通过的值来代替manufacturer_id从清单表列。此列不存在,因此将插入单个 0,并且您永远不会返回制造商。

In the query I wanted to recreate I was constraining by models.id. I could easily access that value in my relationship by defining the foreign key. So the relationship became

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

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

This produces the same query as it did before, but populates the ?with the model_ids. So this returns results, but generally incorrect results. Then I aimed to change the base table that I was selecting from. This value is derived from the model, so I changed the passed in model to Model.

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

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

We've now mimic the model relationship, so that's great I hadn't really got anywhere. But at least now, I could make the join to the manufacturers table. So again I updated the relationship:

我们现在已经模仿了模型关系,所以很好,我还没有真正到任何地方。但至少现在,我可以连接到制造商表。所以我再次更新了关系:

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

This got us one step closer, generating the following query:

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

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

From here, I wanted to limit the columns I was querying for to just the manufacturer columns, to do this I added the select specification. This brought the relationship to:

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

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

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

And got the query to

并得到了查询

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

Now we have a 100% valid query, but the objects being returned from the relationship are of type Modelnot Manufacturer. And that's where the last bit of trickery came in. I needed to return a Manufacturer, but wanted it to constrain by themodelstable in the where clause. I created a new instance of Manufacturer and set the table tomodels` and manually create the relationship.

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

It is important to note, that saving will not work.

重要的是要注意,保存是行不通的

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

This will create a new Manufacturer and then update listings.model_idto the new manufacturer's id.

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