Reputation: 6269
I try to get latest 10 products with its images but only the first image so that is what i try
$newProducts = \App\Product::latest()->with(['images', function($el){
$el->first();
}])->with('category')->take(10)->get();
but it gives me this error
mb_strpos() expects parameter 1 to be string, object given
it has a morph
relation between product
and image
Product Model
class Product extends Model {
public function images()
{
return $this->morphMany(Image::class, 'imageable');
}
}
Image Model
class Image extends Model {
public function imageable()
{
return $this->morphTo();
}
}
Upvotes: 1
Views: 1699
Reputation: 1
public function images()
{
return $this->hasMany(Image::class);
}
public function firstImage()
{
return $this->images()->first();
}
Simply create a function that defines relationship between product and its images. Then create a function that gets the first image
Upvotes: 0
Reputation: 3035
The above solutions are all good. I personally prefer a different solution that I think is gonna be ideal.
I am gonna define a different relationship for a product:
class Product extends Model {
public function images()
{
return $this->morphMany(Image::class, 'imageable');
}
public function firstImage()
{
return $this->morphOne(Image::class, 'imageable');
}
}
So you can access the first image directly or eager load the relationship:
$product->firstImage;
$product->load('firstImage');
Product::with('firstImage');
Just FYI, I learnt about this and other useful database tricks from Jonathan Reinink in Laracon Online 2018.
Upvotes: 2
Reputation: 18916
When using with as a key value array, the $el
parameter to the closure will be a query builder that has not executed yet.
The way to limit query builders of results is to use take()
. Therefor your code should look like this.
->with(['images', function($el) {
$el->take(1);
}])
Edit To make this solution work, you will need an extra package. Using the following trait should make it work and using limit instead. See the following post.
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
->with(['images', function($el) {
$el->limit(1);
}])
Alternatively Laravel solution is to use transformation like properties, where you can create your own custom properties, in the function naming starting with get and ending with attribute.
class Product {
protected $appends = ['first_image'];
public function getFirstImageAttribute() {
return $this->images->first();
}
}
Now if you use standard Laravel
serialization all products will have an first_image field and in your code you can access it like so.
$product->first_image;
To avoid performance hits, include images using with('images')
.
Upvotes: 2