Laravelで閉包テーブル(Closure Table) を簡単に実現してくれるライブラリ ClosureTable

# Laravelで閉包テーブル(Closure Table) を簡単に実現してくれるライブラリ ClosureTable


DBのツリー構造のテーブルにはいくつかありますが、その中に閉包テーブルというものがあります。
この記事にたどり着く人には説明不要だと思うので説明は省きます！！！！

各ツリー構造についてはこちらの記事がわかりやすい気がします！
https://qiita.com/hirashunshun/items/06adf4f42f03a9f3b63d

実際に閉包テーブルを自前で実現しようとすると、CRUDのクエリ投げるときに整合性とれてるのかこれ。。。って部分があり、孫だけ取得とかそのへんのクエリをゴリゴリ書くのは面倒な部分が多く、そこがデメリットな感じもします

## 本題

ゴリゴリクエリ書くのが面倒だなーというデメリットを解決してくれるのがこれ！
https://github.com/franzose/ClosureTable

テーブル構造のことなんて何も考えず脳死で閉包テーブルが作れます！
めちゃくちゃ良いライブラリだと思います

## 使い方 ~Migration編

ライブラリが提供しているコマンドでmigrationを作成

```sh
php artisan closuretable:make --entity=trees
```

すると、migration・Model・Interfaceとかが作られる
```
create  2019_08_19_105450_create_trees_table_migration
create  Tree
create  TreesInterface
create  TreesClosure
create  TreesClosureInterface
```

```php:2019_08_19_105450_create_trees_table_migration
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateTreesTableMigration extends Migration
{
    public function up()
    {
        Schema::create('trees', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('parent_id')->unsigned()->nullable();
            $table->integer('position', false, true);
            $table->integer('real_depth', false, true);
            $table->softDeletes();

            $table->foreign('parent_id')
                ->references('id')
                ->on('trees')
                ->onDelete('set null');
        });

        Schema::create('trees_closure', function (Blueprint $table) {
            $table->increments('closure_id');

            $table->integer('ancestor', false, true);
            $table->integer('descendant', false, true);
            $table->integer('depth', false, true);

            $table->foreign('ancestor')
                ->references('id')
                ->on('trees')
                ->onDelete('cascade');

            $table->foreign('descendant')
                ->references('id')
                ->on('trees')
                ->onDelete('cascade');
        });
    }

    public function down()
    {
        Schema::table('trees_closure', function (Blueprint $table) {
            Schema::dropIfExists('trees_closure');
        });

        Schema::table('trees', function (Blueprint $table) {
            Schema::dropIfExists('trees');
        });
    }
}

```

最低限の構造を作ってくれます。必要であれば、カラムとか追加可能
基本的にはtrees側に追加すればよいかと

interface抜粋

```php:Treeinterface

use Franzose\ClosureTable\Contracts\EntityInterface;

interface treesInterface extends EntityInterface
{
}

```

継承しているInterfaceがClosureTable独自のものになっている


モデル

```php:Tree.php
use Franzose\ClosureTable\Models\Entity;

class trees extends Entity implements treesInterface
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'trees';

    /**
     * ClosureTable model instance.
     *
     * @var treesClosure
     */
    protected $closure = 'App\treesClosure';
}
```

継承しているEntityがClosureTable独自のものになっている


この辺のclass名がloweerCaseなのは気持ち悪いので好みで変える…！

```php
protected $closure = 'App\treesClosure';
```

## 使い方 ~ぷりょぐらむ編

#### 一番上のモデルを作る時

```php
$rootTree = new Tree();
$rootTree->save();
```

普通にモデル作るのと同じ

#### 子供追加

```php
// 親作る
$rootTree = new Tree();
$rootTree->save();

// 子供作る
$childTree = new Tree();
$rootTree->addChild($childTree);
$childTree->save();

// 子供2作る
$childTree2 = new Tree();
$rootTree->addChild($childTree2);
$childTree2->save();
```

これもいい感じにできる

#### 削除

```php
// 親作る
$rootTree = new Tree();
$rootTree->save();

// 子供作る
$childTree = new Tree();
$rootTree->addChild($childTree);
$childTree->save();

// 子供2作る
$childTree2 = new Tree();
$rootTree->addChild($childTree2);
$childTree2->save();

// 子供達だけ削除の場合
$rootTree->deleteSubtree();
// 自分を含む子供達を削除する場合
$rootTree->deleteSubtree(true);
```

#### 取得

```php

$rootTree = Tree::find(いつもの);

// これで子供達とれる(孫まで取れるわけではないので再帰処理とか別メソッドを使う必要がある
$children = $rootTree->getChildren();

```

こんなかんじ

## 書くのが辛くなったのでまとめ

使いやすい！

各メソッドはいい感じに抽象化されてて使いやすい！公式みて！！
https://github.com/franzose/ClosureTable#ancestors

使ってみて！！