I have a fairly common setup – 2 main models and 1 pivot with additional information regarding their relationship. I’m using Laravel API Resources and they work great, but I can’t figure out a way how to display the data without the need of also displaying the pivot data.
Let’s ilustrate with simplified situation:
Models:
class Report extends BaseModel
{
public function reportCountries(): HasMany
{
return $this->hasMany(ReportCountry::class, 'report', 'id');
}
}
class ReportCountry extends BaseModel
{
public function report(): BelongsTo
{
return $this->belongsTo(Report::class, 'report', 'id');
}
public function countryEntity(): BelongsTo
{
return $this->belongsTo(Country::class, 'country', 'id');
}
}
class Country extends BaseModel
{
protected $table = 'countries';
}
The Controller:
class ReportsController
{
public function show(int $id): ReportResource
{
$report = Report::with(['reportCountries.countryEntity'])->findOrFail($id);
return new ReportResource($report);
}
}
And finally the Resources:
/**
* @mixin Report
*/
class ReportResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'countries' => ReportCountryResource::collection($this->whenLoaded('reportCountries')), // I'd love to use CountryResource here instead
// bunch of other data
];
}
}
/**
* @mixin ReportCountry
*/
class ReportCountryResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id, // I don't really need to show this, I'm interested only in CountryResource below:
'country' => new CountryResource($this->whenLoaded('countryEntity')),
];
}
}
/**
* @mixin Country
*/
class CountryResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'title' => $this->title,
];
}
}
What I would love to do is ignore ReportCountryResource
and load CountryResource
directly in ReportResource
, something like this:
/**
* @mixin Report
*/
class ReportResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'countries' => CountryResource::collection($this->whenLoaded('reportCountries.countryEntity')),
// bunch of other data
];
}
}
But when I tried to load this way, the CountryResource
was displaying data from the pivot (ReportCountryResource
) and not from the main model (CountryResource
).
Is there a way how to do this? I’m now creating bunch of Resources for pivot models, which I don’t really need :/
2
Answers
So after more failing and tweaking I got it working by using another
HasManyThrough
relationship.So in my model I now have this:
which allows me to ditch the pivot resources
So I'm using this approach unless someone points something better
Just some small changes and your code should work, no need for pivot resources.
The Controller: