1

I am working on displaying comment replies in my application.

In the controller, I add comments like this:

public function show( $slug )
{
    // Comments
    $commentsQuery  = $this->get_commentQuery( $article->id );
    $comments_count = $commentsQuery->count();

    // If infinite scroll, paginate comments (to be loaded one page per scroll),
    // Else show them all 

    if (boolval($this->is_infinitescroll)) {
        $comments = $commentsQuery->paginate($this->comments_per_page);
    } else {
        $comments = $commentsQuery->get();
    }

    return view( 'themes/' . $this->theme_directory . '/templates/single', array_merge(
        $this->data,
        [
            'categories'        => $this->article_categories,
            'article'           => $article,
            'old_article'       => $old_article,
            'new_article'       => $new_article,
            'comments'          => $comments,
            'comments_count'    => $comments_count,
            'comments_per_page' => $this->comments_per_page,
            'tagline'           => $article->title,
            'is_infinitescroll' => $this->is_infinitescroll
        ]
    ));
} 
/**
 * get_commentQuery
 *
 * @param int $article_id
 * @param int $limit
 * @param int $offset
 *
 * @return object
 */
private function get_commentQuery( int $article_id, int $limit = 0, int $offset = 0 ): object
{
    $commentQuery = Comment::where( [ 'article_id' => $article_id, 'approved' => 1 ] )
        ->orderBy( 'id', $this->comments_orderby_direction );

    if ( $offset > 0 ) {
        $commentQuery = $commentQuery->offset( $offset );
    }
    if ( $limit > 0 ) {
        $commentQuery = $commentQuery->limit( $limit );
    }

    return $commentQuery;
}  

In the blade file that displays the comments - comments-list.blade.php:fv

@foreach ($comments as $comment)
    @if (null == $comment->parent_id)
        <li class="depth-1 comment">
            <div class="comment__avatar">
                <img class="avatar" src="{{ asset('images/avatars/' . $comment->user->avatar) }}" alt="{{ $comment->user->first_name }} {{ $comment->user->last_name }}" width="50" height="50">
            </div>
            <div class="comment__content">
                <div class="comment__info">
                    <div class="comment__author">{{ $comment->user->first_name }} {{ $comment->user->last_name }}</div>
                    <div class="comment__meta">
                        <div class="comment__time">{{ date('jS M Y', strtotime($comment->created_at)) }}</div>
                        @auth
                            <div class="comment__reply">
                                <a class="comment-reply-link" href="#0">Reply</a>
                            </div>
                        @endauth
                    </div>
                </div>
                <div class="comment__text">
                    <p>{{ $comment->body }}</p>
                </div>
            </div>
            @auth
                @include('themes/' . $theme_directory . '/partials/comment-form')
            @endauth
    
            {{-- Comment replies --}}
            @if (count($comment->replies))
                <ul class="children">
                    @foreach ($comment->replies as $reply)
                        <li class="depth-2 comment">
                            <div class="comment__avatar">
                                <img class="avatar" src="{{ asset('images/avatars/' . $reply->user->avatar) }}" alt="{{ $comment->user->first_name }} {{ $comment->user->last_name }}" width="50" height="50">
                            </div>
                            <div class="comment__content">
                                <div class="comment__info">
                                    <div class="comment__author">{{ $reply->user->first_name }} {{ $reply->user->last_name }}</div>
                                    <div class="comment__meta">
                                        <div class="comment__time">{{ date('jS M Y', strtotime($reply->created_at)) }}</div>
                                    </div>
                                </div>
                                <div class="comment__text">
                                    <p>{{ $reply->body }}</p>
                                </div>
                            </div>
                        </li>
                    @endforeach
                </ul>
            @endif
        </li>
    @endif
@endforeach

As the line $commentQuery = Comment::where( [ 'article_id' => $article_id, 'approved' => 1 ] )->orderBy( 'id', $this->comments_orderby_direction ) shows, all comments should be displayd only if aproved.

This does happen for the "parent" comments, but not for comment replies. How can I apply this condition to the replies?

miken32
  • 42,008
  • 16
  • 111
  • 154
Razvan Zamfir
  • 4,209
  • 6
  • 38
  • 252
  • 1
    Side note: why not use Laravels [paginate](https://laravel.com/docs/8.x/pagination#basic-usage) feature? It covers the offset and limit for you. – Paul T. Jun 11 '23 at 21:09

1 Answers1

1
  1. $comment->replies relationship by default fetching all records with no conditions. You need to add where condition to solve this.

  2. You can filter the approved comment by adding the condition the relationship :

private function get_commentQuery( int $article_id, int $limit = 0, int $offset = 0 ): object
{
    $commentQuery = Comment::where( [ 'article_id' => $article_id, 'approved' => 1 ] )
        ->orderBy( 'id', $this->comments_orderby_direction )
        ->with('replies', function($query){
             $query->where('approved', 1);
        });

    if ( $offset > 0 ) {
        $commentQuery = $commentQuery->offset( $offset );
    }
    if ( $limit > 0 ) {
        $commentQuery = $commentQuery->limit( $limit );
    }

    return $commentQuery;
} 

Above query also should be solve your N+1 query problem when fetching $comment->replies in the blade file

fuadps
  • 71
  • 3