Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging results from belongsToMany and belongsTo relationships in Eloquent

In my Image model I have two relationships with my Article model, one many-to-many and one one-to-many:

public function articlesAlbums()
{
    return $this->belongsToMany('Article', 'article_image', 'image_id', 'article_id')->publishedFilter();
}

public function articleThumb()
{
    return $this->hasMany('Article')->publishedFilter();
}

I merge the results from these to get all images used by Article:

public function getArticlesAllAttribute()
{
    return $this->articlesAlbums->merge($this->articleThumb);
}

In my Article model I have two relationships with my Image model:

public function images()
{
    return $this->belongsToMany('Image', 'article_image', 'article_id', 'image_id');
}

public function thumbnail()
{
    return $this->belongsTo('Image', 'image_id');
}

I would like to merge these as well, same way I do in my Image model:

public function getImagesAllAttribute()
{
    return $this->images->merge($this->thumbnail);
}

But that doesn't work, it seems to be because my thumbnail relationship is belongsTo, not hasMany. So maybe it's not a collection. When I try I get an exception:

Call to a member function getKey() on a non-object

I've tried converting it to a collection with:

new Collection($this->thumbnail)

but get an error saying:

__construct() must be of the type array, object given

How can I merge $this->images and $this->thumbnail in my Article model to get the same results that I do in my Image model? Meaning that the results are merged with no duplicates.

Many thanks.

Update:

Since Razor made me realized that $this->thumbnail did not in fact return a collection, but rather a single object it made me rethink if merge was really the proper function to use.

return $this->images->merge($this->thumbnail()->get());

This seemed to cause a lot of unnecessary queries, even though I was eager loading.

So I ended up doing this instead:

public function getImagesAllAttribute()
{
    $imagesAll = $this->images;
    if ( ! is_null($this->thumbnail)) $imagesAll->add($this->thumbnail);

    return $imagesAll->unique();
}

It drastically reduced the number of queries, and the result is the same.

like image 399
Thomas Jensen Avatar asked Sep 28 '14 20:09

Thomas Jensen


1 Answers

$this->thumbnail is the same as $this->thumbnail()->first(), to get a collection, you may try:

public function getImagesAllAttribute()
{
    return $this->images->merge($this->thumbnail()->get());
}
like image 107
Razor Avatar answered Sep 28 '22 01:09

Razor