问题
Currently I am working on a multi domain and language project where videos are reused with different titles and description.
My tables that are relevant to this question with relations look like
posts >- videos >- videos_tags -< tags
id id id id
domain_id video_id
video_id tag_id
Of course I have created the models: Post, Video and Tag with all the required relationships.
The thing I am trying is to get all the posts by my Tag model and maintaining the pagination() functionality.
I am able to get all tags linked to a Post through a Video model. However when I am trying an inverse way I don't seem to keep the pagination() functionality. I have tried a lot but can't seem to find the right solution.
The closest (I think) I have been with this piece of code:
// App\Models\Tag
public function posts()
{
$posts = [];
foreach ($this->videos as $video)
{
foreach ($video->posts as $post)
{
if (!array_key_exists($post->id, $posts)) $posts[$post->id] = $post;
}
}
return \Illuminate\Database\Eloquent\Collection::make($posts);
}
Any suggestions or articles I have missed during my quest for the answer are welcome :)
回答1:
Directly after asking this question I had an eureka moment and found the solution. A way to do this is not by getting the Post models by the Tag model but through the Post model itself.
This is what I did:
// App\Models\Tag
public function posts()
{
return Post
::select('posts.*')
->join('videos', 'posts.video_id', '=', 'videos.id')
->join('videos_tags', 'videos.id', '=', 'videos_tags.video_id')
->join('tags', 'videos_tags.tag_id', '=', 'tags.id')
->where('tags.id', $this->id);
}
This solves the problem of querying a many to many to one relationship and maintaining eloquents functionalities before the query is executed.
回答2:
You could define a so-called scope on your Posts model.
class Post {
/**
* Limit query to posts related to a given tag id.
*
* @param Builder $query The original query
* @param Integer $tag_id The tag id to filter for
* @return Builder The query with an additional where
*/
public function scopeHasTag($query, $tag_id)
{
// assumes that there is a 'tags' relation
return $query->whereHas('tags', function($tags_query) use ($tag_id) {
return $tags_query->where('id', $tag_id);
});
}
}
This scope would allow you to perform a query like the following (hasTags
is laramagically derived from scopeHasTags
).
$posts = Post::query()->hasTag(10); // All posts related with tag id 10
return $posts->paginate();
Here is the official documentation about query scopes: https://laravel.com/docs/5.2/eloquent#local-scopes
来源:https://stackoverflow.com/questions/37393687/laravel-5-2-query-many-to-many-to-one