chu
chu

Reputation: 35

Outputting a reply to a comment

I have add comments to the article, here are all the fields

Schema::create('article_comments', function (Blueprint $table) {
   $table->bigIncrements('id');
   $table->unsignedBigInteger('article_id');
   $table->foreign('article_id')
         ->references('id')->on('articles')->onDelete('cascade');
   $table->string('name');
   $table->string('email');
   $table->text('text');
   $table->string('date');

   $table->unsignedBigInteger('comment_id')->nullable();
   $table->foreign('comment_id')
         ->references('id')->on('article_comments')->onDelete('set null');

   $table->timestamps();
});

I have 2 blocks of comments, one regular and the second answer to it. The only difference between them is the different classes

This is how I bring them out

Normal comment

<div class="comment-list">
    @foreach($article_comments as $article_comment)
    <div class="comment-list__item">
        <div class="item-card">
            <div class="item-card__header">
                <div class="item-card__title">
                    <div class="label">
                        {!! $article_comment->name !!}
                    </div>
                    <div class="data">
                        {!! date('d F Y', strtotime($article_comment->date)) !!}
                    </div>
                </div>
            </div>
            <div class="item-card__content">
                {!! $article_comment->text !!}
            </div>
        </div>
    </div>
    @endforeach
</div>

The reply to him

<div class="comment-sub-list">
    <div class="comment-sub-list__item">
        <div class="item-card">
            <div class="item-card__header">
                <div class="item-card__title">
                    <div class="label">
                        {!! $article_comment->name !!}
                    </div>
                    <div class="data">
                        {!! date('d F Y', strtotime($article_comment->date)) !!}
                    </div>
                </div>
            </div>
            <div class="item-card__content">
                {!! $article_comment->text !!}
            </div>
        </div>
    </div>
</div>

If the comment_id field is filled in, then this will be the answer to the comment with this ID, but I can't implement it

I'm trying to type-check for the presence of the comment_id field and display this comment

$articleCommentsReply = $article_comments->where('comment_id', $article_comment->comment_id)
->whereNotNull('comment_id')
->first();

But in the end, this comment is displayed twice, and one of them is the answer to it

Upvotes: 3

Views: 145

Answers (2)

pr1nc3
pr1nc3

Reputation: 8338

$articleCommentsReply = $article_comments
    ->where('comment_id', $article_comment->comment_id)
    ->first();

You are missing the output of your query (in that case ->first())

That will return you a single collection and then you should be able to access your property like you attempted.

Also an update based on your comment since you are getting nullable comment_ids you can also filter them out by extending your query to :

$articleCommentsReply = $article_comments
    ->where('comment_id', $article_comment->comment_id)
    ->whereNotNull('comment_id')
    ->first();

Upvotes: 1

aimme
aimme

Reputation: 6773

based on my understanding of your question here is what you can do to achieve it.

Here I have assumed the article might have many comments and each comment might have zero or many answers to it with maximum one level recursive.

But You can change answers relationship to just answer by defining it as hasOne relationship if you want and instead of using get() can also use first(). Advantage with this hasMany method is that it will work for both single and multiple related models if you keep it this way.

You can add answers recursive relation to ArticleComment model

//in ArticleComment.php
public function answers()
{
    return $this->hasMany(ArticleComment::class, 'comment_id', 'id');
}

I assume you already have this relationship defined, if not add this comments relationship to Article model.

//in Article.php
public function comments()
{
    return $this->hasMany(ArticleComment::class, 'article_id', 'id');
}

Now you can use following query to fetch the articles with comments. If an answer for that comment exist it will return inside answers relation. If it is just the comment it will return just the comment inside the comments relation and answers will be an empty array.

In the example query below we are looking for comments(with its replies if it has any) of article with id 1. The said article has 2 comments. the first comment has 3 answers to it and second comment does not have any.

$query = Article::where('id', 1)->with(['comments' => function($q) {
            $q->whereNull('comment_id')->with('answers');
        }]);

$output = $query->get()->toArray();

Here is how the output of this query would look like.

[
  {
    "id": 1,
    "text": "article 1"
    "comments": [
      {
        "id": 1,
        "article_id": 1,
        "name": "a1q1",
        "email": "***",
        "text": "Article 1 Comment 1",
        "date": "2021-11-22 16:52:11",
        "comment_id": null
        "answers": [
          {
            "id": 5,
            "article_id": 1,
            "name": "a1q1a1",
            "email": "***",
            "text": "Answer 1 to Article 1 Comment 1",
            "date": "2021-11-22 16:52:11",
            "comment_id": 1
          },
          {
            "id": 6,
            "article_id": 1,
            "name": "a1q1a1",
            "email": "***",
            "text": "Answer 2 to Article 1 Comment 1",
            "date": "2021-11-22 16:52:11",
            "comment_id": 1
          }
        ]
      },
      {
        "id": 2,
        "article_id": 1,
        "name": "a1q2",
        "email": "***",
        "text": "Article 1 Comment 2",
        "date": "2021-11-22 16:52:11",
        "comment_id": null,
        "answers": [
          
        ]
      }
    ]
  }
]

Note: I think the above method is more efficient if you want to display the article,comments and replies in the same page as it does only one query.

If the answer you are looking for is how to separately check and get specific comments you can use following queries.

just the replies to comment id 1

$repliesToCommentOnly = ArticleComment::where('comment_id', $articleComment->id)
    ->get()->toArray();

output

[
  {
    "id": 5,
    "article_id": 1,
    "name": "a1q1a1",
    "email": "***",
    "text": "Answer 1 to Article 1 Comment 1",
    "date": "2021-11-22 16:52:11",
    "comment_id": 1,
    "created_at": "2021-11-22T16:52:11.000000Z",
    "updated_at": "2021-11-22T16:52:11.000000Z"
  },
  {
    "id": 6,
    "article_id": 1,
    "name": "a1q1a1",
    "email": "***",
    "text": "Answer 2 to Article 1 Comment 1",
    "date": "2021-11-22 16:52:11",
    "comment_id": 1,
    "created_at": "2021-11-22T16:52:11.000000Z",
    "updated_at": "2021-11-22T16:52:11.000000Z"
  }
]

article comment with its replies

$commentWitItsReplies = ArticleComment::where('id', 1)->with('answers')
    ->get()->toArray();

output

[
  {
    "id": 1,
    "article_id": 1,
    "name": "a1q1",
    "email": "***",
    "text": "Article 1 Comment 1",
    "date": "2021-11-22 16:52:11",
    "comment_id": null,
    "created_at": "2021-11-22T16:52:11.000000Z",
    "updated_at": "2021-11-22T16:52:11.000000Z",
    "answers": [
      {
        "id": 5,
        "article_id": 1,
        "name": "a1q1a1",
        "email": "***",
        "text": "Answer 1 to Article 1 Comment 1",
        "date": "2021-11-22 16:52:11",
        "comment_id": 1,
        "created_at": "2021-11-22T16:52:11.000000Z",
        "updated_at": "2021-11-22T16:52:11.000000Z"
      },
      {
        "id": 6,
        "article_id": 1,
        "name": "a1q1a1",
        "email": "***",
        "text": "Answer 2 to Article 1 Comment 1",
        "date": "2021-11-22 16:52:11",
        "comment_id": 1,
        "created_at": "2021-11-22T16:52:11.000000Z",
        "updated_at": "2021-11-22T16:52:11.000000Z"
      }
    ]
  }
]

Upvotes: 3

Related Questions