I am querying for a Food
record and its relationships the following way, setting a default value for one of the relation:
$this->foodModel->with(['mainImage', 'category'])->find($foodId);
App\Models\Food
public function category()
{
return $this->belongsTo('App\Models\FoodCategory', 'food_categ_id');
}
public function mainImage()
{
$placeholderUrl = asset('images/placeholders/food.jpg');
return $this->morphOne('App\Models\Media', 'parentable')
->where('primary', 1)
->withDefault([
'url' => $placeholderUrl
]);
}
But now I want to set the default value according to the Food
's category relation for that specific record and I'm not sure how to access the data.
public function mainImage()
{
$placeholderUrl = asset('images/placeholders/food-categories/' . $category->name . '.jpg') // IS IT POSSIBLE?
return $this->morphOne('App\Models\Media', 'parentable')
->where('primary', 1)
->withDefault([
'url' => $placeholderUrl
]);
}
What about to add mainImage into FoodCategory model too and to set default image for each categories?
App\Models\FoodCategory
public function mainImage()
{
return $this->morphOne('App\Models\Media', 'parentable')->where('primary', 1)->withDefault(function (Media $media, FoodCategory $category) {
$media->url = asset('images/placeholders/food-categories/' . $category->name . '.jpg');
});
}
and then into Food model to have Attribute image like this:
App\Models\Food
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = ['image'];
public function image(): Attribute
{
return Attribute::make(
get: fn () => $this->mainImage ?? $this->category->mainImage
);
}
public function mainImage()
{
return $this->morphOne('App\Models\Media', 'parentable')->where('primary', 1);
}
and you need to add category.mainImage for lazy loading too
$this->foodModel->with(['mainImage', 'category', 'category.mainImage'])->find($foodId);
If the food has mainImage the image and mainImage will be the same:
But if the foot does not have mainImage, image will contain the mainImage from the category
{
"id": 3,
"name": "Dr. Reba Dicki",
"food_categ_id": 1,
"image": {
"id": 16,
"parentable_id": "3",
"parentable_type": "App\\Models\\Food",
"primary": 1,
"url": "https://www.kirlin.com/et-consectetur-aliquam-deserunt-fugit-aut-vel-voluptate"
},
"main_image": {
"id": 16,
"parentable_id": "3",
"parentable_type": "App\\Models\\Food",
"primary": 1,
"url": "https://www.kirlin.com/et-consectetur-aliquam-deserunt-fugit-aut-vel-voluptate"
},
"category": {
"id": 1,
"name": "Christophe Hansen"
}
}
... without primary Food media
{
"id": 5,
"name": "Julie Smitham",
"food_categ_id": 5,
"image": {
"id": 5,
"parentable_id": "5",
"parentable_type": "App\\Models\\FoodCategory",
"primary": 1,
"url": "http://www.padberg.info/et-ab-numquam-harum-ut-aut-doloribus.html"
},
"main_image": null,
"category": {
"id": 5,
"name": "Columbus Krajcik",
"main_image": {
"id": 5,
"parentable_id": "5",
"parentable_type": "App\\Models\\FoodCategory",
"primary": 1,
"url": "http://www.padberg.info/et-ab-numquam-harum-ut-aut-doloribus.html"
}
}
}
UPDATE
There is a way withDefault but I'm not prefer this because will make a db query for each:
Update only Food model and mainImage to be:
public function mainImage()
{
return $this->morphOne('App\Models\Media', 'parentable')
->where('primary', 1)
->withDefault(function (Media $media, Food $food) {
$meda = $media->where([
'parentable_type' => FoodCategory::class,
'parentable_id' => $food->food_categ_id,
'primary' => true,
])->first();
if (!$meda) {
$meda = new Media();
$meda->url = asset('images/placeholders/food.jpg');
}
return $meda;
});
}
with Food media
{
"id": 3,
"name": "Dr. Reba Dicki",
"food_categ_id": 1,
"main_image": {
"id": 16,
"parentable_id": "3",
"parentable_type": "App\\Models\\Food",
"primary": 1,
"url": "https://www.kirlin.com/et-consectetur-aliquam-deserunt-fugit-aut-vel-voluptate"
},
"category": {
"id": 1,
"name": "Christophe Hansen"
}
}
without Food media, but with FoodCategory media
{
"id": 5,
"name": "Julie Smitham",
"food_categ_id": 5,
"main_image": {
"id": 5,
"parentable_id": "5",
"parentable_type": "App\\Models\\FoodCategory",
"primary": 1,
"url": "http://www.padberg.info/et-ab-numquam-harum-ut-aut-doloribus.html"
},
"category": {
"id": 5,
"name": "Columbus Krajcik"
}
}
without Food and FoodCategory media
{
"id": 4,
"name": "Clovis Koepp",
"food_categ_id": 4,
"main_image": {
"url": "http://localhost/images/placeholders/food.jpg"
},
"category": {
"id": 4,
"name": "Bernita Kuhn"
}
}
UPDATE 2
For Laravel < 9, you need to use eloquent mutators
App\Models\Food
public function getImageAttribute()
{
return $this->mainImage ?? $this->category->mainImage;
}