多层评论系统 Laravel

2022-08-30 18:34:34

我在使用刀片递归部分视图时遇到了困难。除了文件中的递归之外,大部分工作正常。comment.blade.php

我知道我需要用一个前厅来再次调用自己,但我不知道如何调用它。@include('articles.comments.comment', $comment)

article_comments表:

id
message
user_id
parent_id
created_at
updated_at

应用\文章.php类:

class Article extends Model {

    protected $table = 'articles';

    protected $fillable = [
        'category',
        'title',
        'permalink',
        'synopsis',
        'body',
        'source',
        'show_author',
        'published_at'
    ];

    protected $dates = ['published_at'];

    public function scopePublished($query)
    {
        $query->where('published_at', '<=', Carbon::now());
    }

    public function setPublishedAtAttribute($date)
    {
        $this->attributes['published_at'] = Carbon::parse($date);
    }

    public function comments()
    {
        return $this->hasMany('App\Comments')->where('parent_id', 0);
    }

}

应用\评论.php类:

class Comments extends Model {

    protected $table = 'article_comments';

    protected $fillable = [
        'parent_id',
        'message',
    ];

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

    public function children()
    {
        return $this->hasMany('App\Comments', 'parent_id');
    }

    public function countChildren($node = null)
    {
        $query = $this->children();
        if (!empty($node)) {
            $query = $query->where('node', $node);
        }

        $count = 0;
        foreach ($query->get() as $child) {
            // Plus 1 to count the direct child
            $count += $child->countChildren() + 1; 
        }
        return $count;
    }

}

app\http\Controllers\ArticlesController.php

public function show($permalink)
{
    $article = Article::where('permalink', '=', $permalink)->with('comments','comments.author','comments.children')->first();
    if ($article != null) {
        $comments = $article->comments;
        return view('articles.show', compact('article','comments'));
    } else {
        return redirect('/')->with('error', 'This article does not exist.');
    }
}

resources\views\articles\show.blade.php

@if (count($comments) > 0)
    <ul>
    @foreach ($comments as $comment)
        @include('articles.comments.comment', ['comment'=>$comment])
    @endforeach
    </ul>
@else
    no comments
@endif

资源\视图\文章\注释\注释.blade.php

<li>
    {{ $comment->message }}

    @if (count($comment->children) > 0)
        <ul>
        @foreach ($comment->children as $child)
            @include('articles.comments.comment', ['comment'=>$child])
        @endforeach
        </ul>
    @endif
</li>

当前错误:

Invalid argument supplied for foreach() (View: /var/www/dev.example.com/resources/views/articles/comments/comment.blade.php) (View: 

答案 1

你已经很接近了。我认为这应该有效:

resources\views\articles\show.blade.php

@if (count($comments) > 0)
    <ul>
        @each('articles.comments.comment', $comments, 'comment');
    </ul>
@else
    no comments
@endif

资源\视图\文章\注释\注释.blade.php

<li>
    {{ $comment->message }}

    @if (count($comment->children) > 0)
        <ul>
            @each('articles.comments.comment', $comment->children, 'comment');
        </ul>
    @endif
</li>

app\http\Controllers\ArticlesController.php:

$article = Article::where('permalink', '=', $permalink)->with('comments','comments.author','comments.children')->first();
$comments = $article->comments;
return view('articles.show', compact('article','comments'));

答案 2

首先,我看到您将所有注释放在一个页面中而不进行任何分页,但是,您将模型上的方法限制为仅必须获取根注释的注释。但是,进一步查看您的代码,在您的控制器中,您是延迟加载和前进的。请注意,延迟加载将仅针对第一个父注释发生,之后,所有子项都必须执行大量查询才能通过热切地加载关系来获得它们的关系。comments()Articleparent_id=0comments.authorcomments.children

如果你想把所有的评论放在一个页面中,我建议你删除约束并一次加载所有评论,并应用策略对它们进行排序。下面是一个示例:parent_id=0

应用\文章.php

class Article extends Model {

    // ...

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

}

app\Http\Controllers\ArticlesController.php

use Illuminate\Database\Eloquent\Collection; 

// ...

public function show($permalink)
{
    $article = Article::where('permalink', '=', $permalink)->with('comments','comments.author','comments.children')->first();

    if ($article != null) {

        $comments = $this->buildCommentTree($article->comments);

        return view('articles.show', compact('article','comments'));
    } else {
        return redirect('/')->with('error', 'This article does not exist.');
    }
}


protected function buildCommentTree(Collection $comments, $root = 0)
{
    $branch = new Collection();

    $comments->each(function(Comment $comment) use ($root) {
        if ($comment->parent_id == $root) {

            $children = $this->buildCommentTree($comments, $comment->getKey());

            $branch->push($comment);
        } else {
            // This is to guarantee that children is always a Collection and to prevent Eloquent 
            // from hitting on the database looking for the children
            $children = new Collection();
        }

        $comment->setRelation('children', $children);
    });

    return $branch;

}

现在我们已经对评论进行了排序,而不会惩罚数据库,我们可以开始循环浏览广告了。我更喜欢使用两个文件而不是一个文件进行循环,以便以后可以重用代码。

resources\views\articles\show.blade.php

@if (!$comments->isEmpty())
    @include("articles.comments.container", ['comments'=>$comments])
@else
    no comments
@endif

resources\views\articles\comments\container.blade.php

@if (!$comments->isEmpty())
    <ul>
    @foreach ($comments as $comment)
        @include('articles.comments.show', ['comment'=>$comment])
    @endforeach
    </ul>
@else

资源\视图\文章\注释\显示.blade.php

<li>
    {{ $comment->message }}

    @if (!$comment->children->isEmpty())
        @include("articles.comments.container", ['comments'=>$comment->children])
    @endif
</li>

推荐