Laravel 5: how to do multi threaded comments

2019-02-21 01:55发布

问题:

I am using Laravel Commentable package which uses Nested Sets pattern with Baum.

I have managed to allow users to make comments on posts but they're not threaded, each comment has depth set to zero in the database.

So I'm wondering how does one go about making multi threaded comments like reddit for example?

These are my tables

users: id, name, email...
posts: id, user_id, subreddit_id...
comments: id, body, parent_id, lft, rgt, depth, commentable_id, commentable_type, user_id

My Models (Comment and User)

class Comment extends Model
{
    use Commentable;

    public function commentable()
    {
        return $this->morphTo();
    }

    public function user() {
        return $this->belongsTo('App\User');
    }

    public function posts() {
        return $this->belongsTo('App\Post');
    }
}

class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword;

    public function posts() {
        return $this->hasMany('App\Post');
    }

    public function comments() {
        return $this->hasMany('App\Comment');
    }
}

This is how I'm submitting comments in PostsController

public function createComment($id) {

    $post = Post::with('user.votes')->with('subreddit.moderators')->where('id', $id)->first();

    $comment = new Comment;
    $comment->body = Input::get('comment');
    $comment->user_id = Auth::id();

    $post->comments()->save($comment);
}

And this is the view

    <div class="post-comments">

    {!! Form::open(['route' => ['comment', $post]]) !!}
        <div class="form-group">
            <label for="comment">Your Comment</label>
            <textarea name="comment" class="form-control" rows="3"></textarea>
        </div>
        <button type="submit" class="btn btn-default">Send</button>
    {!! Form::close() !!}

    <div class="comments-nav">
        <ul class="nav nav-pills">
            <li role="presentation" class="dropdown">
                <a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
                    there are {{ count($comments) }} comments <span class="caret"></span>
                </a>
                <ul class="dropdown-menu">
                    <li><a href="#">Best</a></li>
                    <li><a href="#">Hot</a></li>
                </ul>
            </li>
        </ul>
    </div>

    <div class="row">

        <div class="media">
            <!-- first comment -->
            @foreach($comments as $comment)
            <div class="media-heading">
                <button class="btn btn-default btn-xs" type="button" data-toggle="collapse" data-target="#{{ $comment->id }}" aria-expanded="false" aria-controls="collapseExample"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></button> <span class="label label-info">12314</span> {{ $comment->user->name }} 12 hours ago
            </div>

            <div class="panel-collapse collapse in" id="{{ $comment->id }}">

                <div class="media-left">
                    <div class="vote-wrap">
                        <div class="vote up">
                            <i class="glyphicon glyphicon-menu-up"></i>
                        </div>
                        <div class="vote inactive">
                            <i class="glyphicon glyphicon-menu-down"></i>
                        </div>
                    </div>
                    <!-- vote-wrap -->
                </div>
                <!-- media-left -->


                <div class="media-body">
                    <p>{{ $comment->body }}</p>
                    <div class="comment-meta">
                        <span><a href="#">delete</a></span>
                        <span><a href="#">report</a></span>
                        <span><a href="#">hide</a></span>
          <span>
                    <a class="" role="button" data-toggle="collapse" href="#replyCommentT" aria-expanded="false" aria-controls="collapseExample">reply</a>
                  </span>
                        <div class="collapse" id="replyCommentT">
                            <form>
                                <div class="form-group">
                                    <label for="comment">Your Comment</label>
                                    <textarea name="comment" class="form-control" rows="3"></textarea>
                                </div>
                                <button type="submit" class="btn btn-default">Send</button>
                            </form>
                        </div>
                    </div>
                    <!-- comment-meta -->

                </div>
            </div>
            <!-- comments -->
            @endforeach
        </div>
        <!-- first comment -->

    </div>

</div>
<!-- post-comments -->

回答1:

I haven't used Laravel Commentable package, but the docs look pretty good.

I believe you need use Commentable; on your Post model and not your Comment model.

It looks like your Comment model needs to extend Baum\Node and not Model

Then what you have should work.

$post = Post::with('user.votes')->with('subreddit.moderators')->where('id', $id)->first();

$comment = new Comment;
$comment->body = Input::get('comment');
$comment->user_id = Auth::id();

$post->comments()->save($comment);

// or you could do 

$comment->makeChildOf($post);

To make a comment on a comment, it looks like you do something like this. I would probably make a CommentsController.

public function addComment(Request $request){
    $parent = Comment::find(Input::get('parent_id'));

    $comment = new Comment;
    $comment->body = Input::get('comment');
    $comment->user_id = Auth::id();

    $comment->makeChildOf($parent);
}

The Relations, Root and Leaf scopes, Accessing the ancestry/descendancy chain section of the docs have several examples on how to then retrieve the comments for comments.

Edit

It looks like the Comment model in the package already extends the Baum\Node so you don't need to do that. In order to use this package, it looks like you need to use his Comment model. I am sure you could use his model as a base and roll your own.

You could do something like this. You would have to set up a route.

<div class="collapse" id="replyCommentT">    

    {!! Form::open(['route' => ['comment', $comment]]) !!}

        <input type="hidden" name="parent_id" value="{{ $comment->id }}"/>

        <div class="form-group">

            <label for="comment">Your Comment</label>

            <textarea name="comment" class="form-control" rows="3"></textarea>

        </div>

        <button type="submit" class="btn btn-default">Send</button>

    {!! Form::close() !!}

</div>