laravel-nestedsetでデータをネストで扱う方法

#はじめに
ページのカテゴリなどで使うデータをlaravel-nestedsetでネストで扱う方法を記載します。

・Laravel-nestedset 公式URL
https://github.com/lazychaser/laravel-nestedset

##環境
・PHP 8.0.1
・Laravel 8.40.0

##1. laravel-nestedのインストール

```
php composer.phar require kalnoy/nestedset:5.0.3
```

##2. マイグレーションファイルにnestedをセットする。

```
class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('categories', function (Blueprint $table): void {
            $table->increments('id');
            $table->string('name');

            // '_lft' / '_rgt' / 'parent_id' が追加される
            $table->nestedSet();
        });
    }
```

マイグレーションを実行する

```
php artisan migrate:fresh
```

テーブルを確認する。「_lft」, 「_rgt」 「parent_id」 が追加される。

```
mysql> show columns from categories;
+-----------+------------------+------+-----+---------+-------------------+
| Field     | Type             | Null | Key | Default | Extra             |
+-----------+------------------+------+-----+---------+-------------------+
| id        | int(10) unsigned | NO   | PRI | NULL    | auto_increment    |     
| name      | varchar(100)     | NO   |     | NULL    |                   |
| _lft      | int(10) unsigned | NO   | MUL | NULL    |                   |
| _rgt      | int(10) unsigned | NO   |     | NULL    |                   |
| parent_id | int(10) unsigned | YES  |     | NULL    |                   |
+-----------+------------------+------+-----+---------+-------------------+
```

##3. カテゴリの登録

```
Category::create([
    'name' => '大カテゴリ',
    'children' => [
        [
            'name' => '中カテゴリ',
            'children' => [
                [ 'name' => '小カテゴリ' ],
            ],
        ],
    ],
]);
```

createを実行しデータを確認すると、以下のようなデータで登録される。

```
+------+------+-----------+----+--------------+
| _lft | _rgt | parent_id | id | name         | 
+------+------+-----------+----+--------------+
|    1 |    6 |      NULL |  1 | 大カテゴリ     | 
|    2 |    5 |         1 |  2 | 中カテゴリ     | 
|    3 |    4 |         2 |  3 | 小カテゴリ     | 
+------+------+-----------+----+--------------+
```

以下のようにも登録が可能。

```
$parent = Category::create(['name' => '大カテゴリ']); 
$children = Category::create(['name' => '中カテゴリ']); 
$children->appendTo($parent)->save();
```

##4. データ取得について

大カテゴリーの子孫(descendants)をリスト型式で取得する。

```
$parent = Category::find(1); // 大カテゴリー(id=1)
$categories = $parent->descendants()->get(); // 中カテゴリー、小カテゴリーをリストで取得
dd($categories->toArray()); // 配列形式で表示

-- データ結果 --
array:3 [
  0 => array:5 [
    "id" => 2
    "name" => "中カテゴリ"
    "_lft" => 2
    "_rgt" => 5
    "parent_id" => 1
  ]
  1 => array:15 [
    "id" => 3
    "name" => "小カテゴリ"
    "_lft" => 3
    "_rgt" => 4
    "parent_id" => 2
  ]
]
```

カテゴリーの先祖(ancestors)をリストで取得する。

```
$small = Category::find(3); // 小カテゴリー(id=3)
$categories = $small->ancestors()->get(); // 大カテゴリー、中カテゴリーをリストで取得
dd($categories->toArray()); // 配列形式で表示

-- データ結果 --
array:2 [
  0 => array:5 [
    "id" => 1
    "name" => "大カテゴリ"
    "_lft" => 1
    "_rgt" => 6
    "parent_id" => null
  ]
  1 => array:5 [
    "id" => 2
    "name" => "中カテゴリ"
    "_lft" => 2
    "_rgt" => 5
    "parent_id" => 1
  ]
]
```

カテゴリーをツリー形式(ネスト)で取得する。

```
$tree = Category::get()->toTree(); // ツリー形式(ネスト)で取得
dd($tree->toArray()); // 配列形式で表示

-- データ結果 --
array:1 [
  0 => array:6 [
    "id" => 1
    "name" => "大カテゴリ"
    "_lft" => 1
    "_rgt" => 6
    "parent_id" => null
    "children" => array:1 [
      0 => array:6 [
        "id" => 2
        "name" => "中カテゴリ"
        "_lft" => 2
        "_rgt" => 5
        "parent_id" => 1
        "children" => array:1 [
          0 => array:6 [
            "id" => 3
            "name" => "小カテゴリ"
            "_lft" => 3
            "_rgt" => 4
            "parent_id" => 2
            "children" => []
          ]
        ]
      ]
    ]
  ]
]
```

親カテゴリ(一番上位のカテゴリ）をリスト形式で取得する。

```
// カテゴリを登録
$parent = Category::create(['name' => '大カテゴリ']);
$parent2 = Category::create(['name' => '大カテゴリ2']);
$children = Category::create(['name' => '中カテゴリ']); 
$children->appendTo($parent1)->save();

// 親カテゴリ(一番上位のカテゴリ）をリスト形式で取得する。
$categories = Category::first()->whereIsRoot()->get();
dd($categories->toArray()); // 配列形式で表示

-- データ結果 --
array:2 [
  0 => array:5 [
    "id" => 1
    "name" => "大カテゴリ"
    "_lft" => 1
    "_rgt" => 2
    "parent_id" => null
  ]
  1 => array:5 [
    "id" => 2
    "name" => "大カテゴリ2"
    "_lft" => 3
    "_rgt" => 8
    "parent_id" => null
  ]
]
```