I have a model Listing that inherits through its belongsTo('Model') relationship should inherently belong to the Manufacturer that its corresponding Model belongs to.
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.
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');
}
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.
It took a bit of finagling, to get your requested solution working. The solution looks like this:
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:
The query that would be normally created by doing
return $this->belongsTo('Manufacturer');
The
?
would be replaced by the value ofmanufacturer_id
columns from the listings table. This column doesn't exist, so a single 0 would be inserted and you'd never return a manufacturer.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 becameThis 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 toModel
.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:
This got us one step closer, generating the following query:
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.*'));
And got the query to
Now we have a 100% valid query, but the objects being returned from the relationship are of type
Model
notManufacturer
. And that's where the last bit of trickery came in. I needed to return aManufacturer, but wanted it to constrain by the
modelstable in the where clause. I created a new instance of Manufacturer and set the table to
models` and manually create the relationship.It is important to note, that saving will not work.
This will create a new Manufacturer and then update
listings.model_id
to the new manufacturer's id.