Laravel 5.2 | query many to many to one

守給你的承諾、 提交于 2019-12-24 00:59:45

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!