Laravelで閉包テーブル(Closure Table) を簡単に実現してくれるライブラリ ClosureTable
DBのツリー構造のテーブルにはいくつかありますが、その中に閉包テーブルというものがあります。
この記事にたどり着く人には説明不要だと思うので説明は省きます!!!!
各ツリー構造についてはこちらの記事がわかりやすい気がします!
https://qiita.com/hirashunshun/items/06adf4f42f03a9f3b63d
実際に閉包テーブルを自前で実現しようとすると、CRUDのクエリ投げるときに整合性とれてるのかこれ。。。って部分があり、孫だけ取得とかそのへんのクエリをゴリゴリ書くのは面倒な部分が多く、そこがデメリットな感じもします
本題
ゴリゴリクエリ書くのが面倒だなーというデメリットを解決してくれるのがこれ!
https://github.com/franzose/ClosureTable
テーブル構造のことなんて何も考えず脳死で閉包テーブルが作れます!
めちゃくちゃ良いライブラリだと思います
使い方 ~Migration編
ライブラリが提供しているコマンドでmigrationを作成
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
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抜粋
use Franzose\ClosureTable\Contracts\EntityInterface;
interface treesInterface extends EntityInterface
{
}
継承しているInterfaceがClosureTable独自のものになっている
モデル
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なのは気持ち悪いので好みで変える…!
protected $closure = 'App\treesClosure';
使い方 ~ぷりょぐらむ編
一番上のモデルを作る時
$rootTree = new Tree();
$rootTree->save();
普通にモデル作るのと同じ
子供追加
// 親作る
$rootTree = new Tree();
$rootTree->save();
// 子供作る
$childTree = new Tree();
$rootTree->addChild($childTree);
$childTree->save();
// 子供2作る
$childTree2 = new Tree();
$rootTree->addChild($childTree2);
$childTree2->save();
これもいい感じにできる
削除
// 親作る
$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);
取得
$rootTree = Tree::find(いつもの);
// これで子供達とれる(孫まで取れるわけではないので再帰処理とか別メソッドを使う必要がある
$children = $rootTree->getChildren();
こんなかんじ
書くのが辛くなったのでまとめ
使いやすい!
各メソッドはいい感じに抽象化されてて使いやすい!公式みて!!
https://github.com/franzose/ClosureTable#ancestors
使ってみて!!