I'm trying to get the related posts of a post, based on its tags.

My post (id 1) has several tags attached to it, i.e. tag (id 1-3) this means that my post has 3 tags. Based on those tags, I'd like to show other posts that have this tag(s).

My Tag Model:

<?php namespace Digitus\Base\Model;

class Tag extends \Eloquent{

    protected $table = 'tags';
    protected $guarded = ['id'];
    protected $fillable = ['name'];

    public function posts()
    {
        $this->belongsToMany('Digitus\Base\Model\Post');
    }

}

My post model:

    <?php namespace Digitus\Base\Model;

class Post extends \Eloquent {

    protected $fillable = array('title','body', 'author','slug');

    public function user()
    {
        return $this->belongsTo('Digitus\Base\Model\User', 'author');
    }

    public function tags()
    {
        return $this->belongsToMany('Digitus\Base\Model\Tag');
    }

    public function comments()
    {
        return $this->belongsToMany('Digitus\Base\Model\Comment');
    }

    public function categories()
    {
        return $this->belongsToMany('Digitus\Base\Model\Categorie');
    }
}

In my view I currently have:

<div class="col-xs-8 col-sm-8 col-md-8 col-lg-8 panel panel-info">
    <p>Gerelateerde berichten:</p>

            <?php 
            $posts = Digitus\Base\Model\Post::all();
            $tags = Digitus\Base\Model\Tag::all(); ?>
            @foreach($posts as $post)   
                @foreach($post->tags as $tag)
                    <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">{{ $post->title }}</div>
                @endforeach
            @endforeach


</div>

But it doesn't really show the posts which have the same tags, it just throws all my posts out. Also, I tried adding some sort of filter to it, so there won't be any duplicate posts (same post show up 2+ times) but this also failed at my end.

I'm not looking for direct answers, more for directions and suggestions etc.

有帮助吗?

解决方案

This will do, but mind there will be run 3 db queries, so maybe you'd like some joins instead

<?php 
// don't do this in the view, better in controller, service or whatever and just pass $posts to the view
$posts = Digitus\Base\Model\Post::with('tags.posts')->get();
?>
@foreach($posts as $parentPost)
    @foreach($parentPost->tags as $tag)
        @foreach($tag->posts as $post)
            <?php if($post->id == $parentPost->id) continue; ?>
            <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">{{ $post->title }}</div>
        @endforeach
    @endforeach
@endforeach

----- edit: In your Tag model you don't return nothing from relation, so just add return:

public function posts()
{
   return $this->belongsToMany('Digitus\Base\Model\Post');
}

其他提示

In this code:

@foreach($posts as $post)   
     @foreach($post->tags as $tag)
         <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">{{ $post->title }}</div>
     @endforeach
@endforeach

you are iterating over all tags of all posts, and outputting the post title.

So for a post that has 3 tags, you will output the post title 3 times.

What you might do is this:

<?php $posts = Digitus\Base\Model\Post::with('Tags.Posts')->get(); ?>
@foreach ($posts as $post)
    @foreach ($post->tags as $tag)
        @foreach ($tag->posts as $relatedPost)
            <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">{{ $relatedPost->title }}</div>
        @endforeach
    @endforeach
@endforeach

Not tested, but as far as I understand how Eloquent eager loading works, it should work.

EDIT:

The above would output all posts actually, so if you want the related posts of a single post, this is the way to go:

The following should output an array with a single post in it:

<?php $posts = Digitus\Base\Model\Post::with('tags.posts')->where('id', $id)->get(); ?>

which you then 'iterate' over:

@foreach ($posts as $post)
    @foreach ($post->tags as $tag)
        @foreach ($tag->posts as $relatedPost)
            <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">{{ $relatedPost->title }}</div>
        @endforeach
    @endforeach
@endforeach
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top