Laravelでkalnoy/nestedsetを使って入れ子集合モデルのコメント機能を作る方法

入れ子集合モデルで作るコメント機能

LaravelでYouTubeのようなコメント機能を作成する方法を解説します。

YouTubeのようなコメント機能とは、親コメントに返信したり子コメントに返信することができ、その流れに沿ってコメントが表示されるものです。

コメント機能表示画面

入れ子集合モデルとは?

今回のコメント機能は、「入れ子集合モデル」という概念を採用しています。むずかしい話は省略して簡単に図で表すと、次のようになります。

入れ子集合モデルの例1

親が1つ目のコメント、子が親に対する返信、孫が子に対する返信です。

それぞれの子孫が中に入っていく仕組みで、子孫が増えるたびに両端の数値が大きくなっていきます。

そして、その数値の変動は他の親コメントや子コメントにも影響します。

例えば、右のオレンジ色の親コメントにもう1つ子コメントが入るとこのようになります。

入れ子集合モデルの例2

この左右の数値をDBで管理する仕組みを作ります。

kalnoy/nestedsetの使い方

コメントが増えるたびに全てのコメントの左右の数値が変化するので大変です。

しかし、Laravelなら便利なパッケージがあるから大丈夫!というわけで、kalnoy/nestedsetの使い方を見ていきましょう。

1:kalnoy/nestedsetインストール

まずはターミナルでインストールします。

composer require kalnoy/nestedset

2:DBマイグレーション

nestedsetを使う場合は、マイグレーションファイルに下記を追加します。

public function up()
    {
        Schema::create('comments', function (Blueprint $table) {
            $table->nestedSet();
        });
    }
public function down()
    {
        Schema::table('comments', function (Blueprint $table) {
         $table->dropNestedSet();
     });
    }

これで、入れ子構造の左右の数値を管理するカラムと、親コメントのidを管理するカラムが追加されます。

マイグレーション後のDB
lftはleftでrgtはright

ちなみにこの書き方はLaravel 5.5以上の場合です。

マイグレーションファイルには、他にも用途に合わせて必要なものを記入しましょう。

3:Commentモデルに追記

Commentモデルに下記を追記します。nestedsetを使うために必要です。

namespace App;

use Illuminate\Database\Eloquent\Model;
use Kalnoy\Nestedset\NodeTrait; //追記

class Comment extends Model
{
    use NodeTrait; //追記
}

4:tinkerでtreeをfixする

これは、コメントが追加されるたびに数値がアップデートされる_lftカラムと_rgtカラムを管理するために必要な作業です。

これをせずにパッケージ特有のメソッドを使うと、Node must existsというエラーが出てしまいますのでご注意。

ターミナルを開き、tinkerを起動します。

$ php artisan tinker

次に、該当のモデルをfixTree()します。

>>> Comment::fixTree();

もしかしたら次のようなエラーがですかもしれません。

PHP Fatal error:  Class ‘Comment’ not found in Psy Shell code on line 1

その場合は、次のようにAppから打ってください。

>>> App\Comment::fixTree();

これで準備は万端です!

親コメントと子コメントの登録

kalnoy/nestedsetにはさまざまなメソッドが用意されています。

まずは親コメントの登録はLaravelのクエリビルダそのままです。

$comment = new Comment($attributes);
$comment->save(); 

子コメントの登録には、たくさんのメソッドが用意されています。

$child->appendToNode($parent)->save();
//または
$parent->appendNode($child);
//または
$child->parent()->associate($parent)->save();
// またはシンプルにLaravelのメソッドで
$child->parent_id = $parent->id;
$child->save();

これらは主にコメントが新規追加されたときにDBへ保存する方法として使えます。

他にも、既存のコメントを一番上の親に移動したり、任意のコメントの隣に移動する方法などがあります。詳しくはコチラ

以上で〜す!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)