31789
お世話になります。どうかご教授頂けませんでしょうか。  
サイト作成で、商品に関するコメント一覧ページを作成しております。その一覧で、ある商品のコメントに対する返信、つまりコメントに対するコメント（子コメント）を以下の様にコメントA（親コメント）の下に延々と表示できるようにしたいのですが、現在の状況はその下の様な状況になっており、同じコメントAが重複されます。

・期待する表示

```

    コメントA
       コメントAに対するコメントa1
           コメントAに対するコメントa2
           コメントAに対するコメントa3
           コメントAに対するコメントa4
    
    コメントB
           ………………………………………
           ……………………………………….
    コメントC
           ………………………………………
           ……………………………………….
    
```

・ 現在の表示

```

    コメントA
          コメントAに対するコメントa1
    コメントA
          コメントAに対するコメントa2
    コメントA
          コメントAに対するコメントa3
    コメントA
          コメントAに対するコメントa4
    
    コメントB
           ………………………………………
           ……………………………………….
    コメントC
           ………………………………………
           ……………………………………….
    
```

以下は以上の設定の必要最小限を記載したDB、PHP、Smartyでの記述でございます。問題点は何かをご指摘いただけませんでしょうか。あるいはこのようなケースの場合、どのような設定にするのが最適かご教授頂けませんでしょうか。

DB

```

    親コメント用テーブル（dtb_review）     
    review_id                              
    product_id                              
    reviewer_name                         
    Comment                                                          
    Create_date
    
    子コメント用テーブル（dtb_review2）
    review_id
    original_review_id
    reviewer_name
    comment
    Create_date
    
    *dtb_reviewのreview_idとdtb_review2のoriginal_review_idは同じid（番号）です。
    
```

PHP

```

    $col = "t1.review_id, t1.comment, t1.del_flg, t1.create_date, t1.product_id, t1.reviewer_name, t2.product_id, t5.original_review_id, t5.comment2, t5.reviewer_name, t5.create_date";
    
    $from = "dtb_review as t1 
    left join dtb_products as t2 using (product_id)
    left join dtb_review2 as t5 ON t1.review_id = t5.original_review_id";
    
    $where = " t1.del_flg = 0 ORDER BY t1.create_date DESC";
    
    $this->arrReview = $objQuery->select($col, $from, $where, $arrval); 
    
```

Smarty

```

    {section name=cnt loop=$arrReview}
    
    {$arrReview[cnt].comment|h|nl2br}（親コメント）
    
    {if $arrReview[cnt].review_id|h == $arrReview[cnt].original_review_id|h }
    
    {section2 name=cnt loop=$arrReview}
    
    {$arrReview[cnt].comment2|h|nl2br}（子コメント）
    
    {/section2}
    
    {else}
    {/if}
    
    {/section}
    
```

*あるコメントに対してコメントされると、つまり親コメントに対して子コメントが作成されるとdtb_reviewのreview_idがdtb_review2のoriginal_review_idに渡ります。
CC BY-SA 4.0
2017-01-09T16:50:59.827
31733
2021-03-16T23:29:19.523
2021-03-16T23:29:19.523
3060
19211
question
php smarty
コメント一覧でコメントに対するコメントが正しく表示される記述方法をお教え願います。
親コメント、子コメントとそれぞれテーブルを分けていることで分かりにくくなっているのではないでしょうか？  
このケースの場合、dtb_reviewと、productテーブルのみで実装可能です。

```

    //reviewテーブル
    review_id 
    parent_review_id //親コメントの場合はNULL, 子コメントの場合は親のreview_id                             
    product_id                              
    reviewer_name                         
    comment                                                          
    create_date
    
```

parent_review_idには、親コメントの場合はNULL,子コメントの場合は親コメントのreview_idが挿入されるようにします。(サンプル内dtb_review2のoriginal_review_idのような役割です)

sql

```

    SELECT
      t1.review_id,
      t1.parent_review_id,
      t1.comment,
      t1.del_flag,
      t1.create_date,
      t1.product_id,
      t1.reviewer_name,
      t2.product_id,
      CASE WHEN t1.parent_review_id IS NULL THEN t1.review_id ELSE t1.parent_review_id END as root_review_id
    FROM dtb_review AS t1
      LEFT JOIN dtb_products AS t2 ON t1.product_id = t2.product_id
    WHERE t1.del_flag = 0 ORDER BY root_review_id;
    
```

CASE .... AS root_review_id
の箇所では、親コメントなら自身のreview_id,子コメントなら親コメントのreview_idを取得して、このroot_review_id
を利用してORDER BY しています。

このようにすることで、  
コメントA  
コメントAの返信a  
コメントAの返信b  
コメントAの返信c  
コメントB  
・  
・  
・  
といった順番で取得できるようになりますので、あとはテンプレートループ内でparent_review_idの値によって親コメントか、子コメントかを判別して出力するといった形が最善でしょう。

```

    <dl>
    {section name=cnt loop=$arrReview}
        {if $arrReview[cnt].parent_review_id == null} {* 親コメント parent_review_idがnullかチェック *}
            <dt>親コメント</dt>
        {else}
            <dd>子コメント</dd>
        {/if}
    {/section}
    </dl>
    
```

* * *

## 更新

親コメントの書き込み時間が新しい順にSQLを修正してみます。

SQL

```

    SELECT
      t1.review_id,
      t1.parent_review_id,
      t1.comment,
      t1.del_flag,
      t1.create_date,
      t1.product_id,
      t1.reviewer_name,
      t2.product_id,  
      t3.create_date, //親コメントの作成日時
      CASE WHEN t1.parent_review_id IS NULL THEN t1.review_id ELSE t1.parent_review_id END as root_review_id
    FROM review AS t1
      LEFT JOIN product AS t2 ON t1.product_id = t2.product_id
      LEFT JOIN review as t3 ON ( CASE WHEN t1.parent_review_id IS NULL THEN t1.review_id ELSE t1.parent_review_id END ) = t3.review_id
    WHERE t1.del_flag = 0 
    ORDER BY t3.create_date DESC, t1.create_date ASC;
    
```

新たにLEFT JOIN句を追加しました。  
これはparent_review_idを元に同じreviewテーブルをJOINし、親コメントの作成日時で並び替えを行っています。

並び替えの優先順序は

  1. 親コメントの作成日時(降順)
  2. 子コメントの作成日時(昇順)

これでご希望の動作になるかと思います。
CC BY-SA 3.0
2017-01-12T05:24:30.030
31789
2017-01-17T15:03:37.480
2017-01-17T15:03:37.480
13097
13097
31733
answer