ぐぐると検索の下の方に出てくる話題ではありますが、忘れがちなので備忘録としてここにも書いておきたいと思います。
Laravel のプラグインである AdminLTE3 において、左ペインのメニューを構成するには通常、config/adminlte.php の menu キーを使用します。しかし、例えばユーザに admin レベルを設定したいという場合はこの方法が使えません。そこで動的にメニューを追加する必要が出てきます。
AdminLTE3 のマニュアルを読むと、以下のような方法を取ればよいことが分かります。ここでは一例として、メニューを DB テーブルに保存する方法を紹介します。
DBに入れるメニューですが、以下のような構造とします。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('menus', function (Blueprint $table) {
$table->id();
$table->tinyInteger('flg_admin')->default(0)->comment('ADMIN なら1');
$table->string('title', 1024)->comment('タイトル');
$table->string('icon', 1024)->nullable(true)->comment('icon html');
$table->string('link', 1024)->nullable(true)->comment('リンク先 URL');
$table->unsignedBigInteger('parent_id')->nullable(true)->comment('親 メニュー ID');
$table->integer('sort_number')->default(0)->index()->comment('表示順序');
$table->datetime('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
$table->datetime('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('menus');
}
};
要点となるのは、flg_adminでメニューを切り替える点、parent_idでサブメニューが作成できるようにしている点、sort_number で表示順序を定義している点です。また、users テーブルに flg_admin カラムを追加し、どのユーザが admin であるか示すように修正します。
さて、本題ですが、app/Providers/EventServiceProvider.php の boot 関数に以下を追加します。
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use JeroenNoten\LaravelAdminLte\Events\BuildingMenu;
use App\Models\Menu;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* @var array<class-string, array<int, class-string>>
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
Event::listen(function (BuildingMenu $event) {
$pmenus = Menu::whereNull('parent_id');
if (!auth()->user()->flg_admin) {
$pmenus = $pmenus->where('flg_admin', 0);
}
$pmenus = $pmenus->orderBy('sort_number')->get();
foreach ($pmenus as $pmenu) {
$menu = [ 'text' => $pmenu->title ];
if ($pmenu->icon) {
$menu['icon'] = $pmenu->icon;
}
if ($pmenu->link) {
$menu['url'] = url($pmenu->link);
}
$submenus = [];
$cmenus = Menu::where('parent_id', $pmenu->id);
if (!auth()->user()->flg_admin) {
$cmenus = $cmenus->where('flg_admin', 0);
}
$cmenus = $cmenus->orderBy('sort_number')->get();
foreach ($cmenus as $cmenu) {
$submenu = [ 'text' => $cmenu->title ];
if ($cmenu->icon) {
$submenu['icon'] = $cmenu->icon;
}
if ($pmenu->link) {
$menu['url'] = url($pmenu->link);
}
$submenus = [];
$cmenus = Menu::where('parent_id', $pmenu->id);
if (!auth()->user()->flg_admin) {
$cmenus = $cmenus->where('flg_admin', 0);
}
$cmenus = $cmenus->orderBy('sort_number')->get();
foreach ($cmenus as $cmenu) {
$submenu = [ 'text' => $cmenu->title ];
if ($cmenu->icon) {
$submenu['icon'] = $cmenu->icon;
}
if ($cmenu->link) {
$submenu['url'] = url($cmenu->link);
}
$submenus[] = $submenu;
}
if (count($submenus) > 0) {
$menu['submenu'] = $submenus;
}
$event->menu->add($menu);
}
});
}
/**
* Determine if events and listeners should be automatically discovered.
*
* @return bool
*/
public function shouldDiscoverEvents()
{
return false;
}
}
ここでの要点は “use JeroenNoten\LaravelAdminLte\Events\BuildingMenu;” を追加することと、listen() 関数呼び出しを追加することです。ぐぐるとlisten の第1引数に BuildingMenu::class を設定している場合もありますが、Laravel では Data Injection 機能が使えるので、必ずしも必要ではありません。
メニューを構成したら、最後に $event->menu->add() でメニューの最後に追加します。
コメントを残す