Implementation of laravel 5 ~ nested comments

Time:2020-11-6

Often we see that there are many forms of comment display, such as’ @ ‘so and so, or like Zhihu’s contractive comment, or nested comment. Then the most common form of comment is nested comment, because this is more eye-catching

preparation
1. Design three tables: users, posts and comments. The table structure is as follows:

users

Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

posts

Schema::create('posts', function (Blueprint $table) {
    $table->increments('id');
    $table->string('title');
    $table->integer('user_id')->index();
    $table->text('content');
    $table->timestamps();
});

comments

Schema::create('comments', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('user_id')->index();
    $table->integer('post_id')->index();
    $table->integer('parent_id')->index()->default(0);
    $table->text('body');
    $table->timestamps();
});

2. Model layer:
Post.php file

/**
 *An article has multiple comments
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function comments()
{
    return $this->hasMany(Comment::class);
}

/**
 *Get a comment on this article as parent_ ID to group
 * @return static
 */
public function getComments()
{
    return $this->comments()->with('owner')->get()->groupBy('parent_id');
}

Comments.php file

/**
 *The user of this comment
 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 */
public function owner()
{
    return $this->belongsTo(User::class, 'user_id');
}

/**
 *Sub comments of this comment
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function replies()
{
    return $this->hasMany(Comment::class, 'parent_id');
}

Logic writing
In fact, the nested comments we want to implement have some ideas in our preparation work. We first display an article, and at the same time use the one to many relationship between articles and comments to display all comments. However, one field involved in our comments is parent_ ID, this field is very special. We use this field to group. The code is return $this > comments() – > with (‘owner ‘) – > get() – > groupby (‘parent’)_ The specific process is as follows:

web.php file

\Auth:: loginusingid (1); // login with user ID 1

//Displays the article and the corresponding comments
Route::get('/post/show/{post}', function (\App\Post $post) {
    $post->load('comments.owner');
    $comments = $post->getComments();
    $comments['root'] = $comments[''];
    unset($comments['']);
    return view('posts.show', compact('post', 'comments'));
});

//User comments
Route::post('post/{post}/comments', function (\App\Post $post) {
    $post->comments()->create([
        'body' => request('body'),
        'user_id' => \Auth::id(),
        'parent_id' => request('parent_id', null),
    ]);
    return back();
});

View code
In view, we need to implement nesting. As users comment on each other more and more, there will be more levels of nesting. Therefore, we need to use various tips to display the whole comment. We use the @ include() function to display the whole comment. Then we try to construct the following structure:

 - comments
comments.blade.php
form.blade.php
list.blade.php

 - posts
show.blade.php

The code is as follows:
show.blade.php

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="//cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" style="margin-top: 100px">
    <div class="col-md-10 col-md-offset-1">
        <h2>{{$post->title}}</h2>
        <h4>{{$post->content}}</h4>
        <hr>
        @include('comments.list',['collections'=>$comments['root']])
        <h3>Leave your comments</h3>
        @include('comments.form',['parentId'=>$post->id])
    </div>
</div>
</body>
</html>

comment.blade.php

<div class="col-md-12">
    <h5><span style="color:#31b0d5">{{$comment->owner->name}}</span>:</h5>
    <h5>{{$comment->body}}</h5>

    @include('comments.form',['parentId'=>$comment->id])

    @if(isset($comments[$comment->id]))
        @include('comments.list',['collections'=>$comments[$comment->id]])
    @endif
    <hr>
</div>

form.blade.php

<form method="POST" action="{{url('post/'.$post->id.'/comments')}}" accept-charset="UTF-8">
    {{csrf_field()}}

    @if(isset($parentId))
        <input type="hidden" name="parent_id" value="{{$parentId}}">
    @endif

    <div class="form-group">
        <label for="body" class="control-label">Info:</label>
        <textarea id="body" name="body"  class="form-control" required="required"></textarea>
    </div>
    < button type = "submit" class = "BTN BTN success" > reply < / button >
</form>

list.blade.php

@foreach($collections as $comment)
    @include('comments.comment',['comment'=>$comment])
@endforeach

The final effect is as followsImplementation of laravel 5 ~ nested comments

Recently, when I was studying laravel, I saw a function that I had done before, but I wrote it down in detail.
Excerpt from:
https://laravel-china.org/art…
https://laravel-china.org/art…