😆Package spatie/menu full phần 4 tách ra để nghiên cứu (ok)

Xem cách xác thực bằng permission, bài này xác thực bằng can

function __construct()
    {
        // set permission
         $this->middleware('permission:user-list|user-create|user-edit|user-delete', ['only' => ['index','show']]);
         $this->middleware('permission:user-create', ['only' => ['create','store']]);
         $this->middleware('permission:user-edit', ['only' => ['edit','update']]);
         $this->middleware('permission:user-delete', ['only' => ['destroy']]);
    }

Part 1: Tạo trang quản trị roles,users,permissions

User

Role

Permission

C:\xampp82\htdocs\lva3\app\Http\Controllers\Admin\UserController.php

<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Spatie\Permission\Models\Role;

class UserController extends Controller
{
  public function __construct()
  {
    $this->middleware('can:user list', ['only' => ['index', 'show']]);
    $this->middleware('can:user create', ['only' => ['create', 'store']]);
    $this->middleware('can:user edit', ['only' => ['show', 'edit']]);
    $this->middleware('can:user delete', ['only' => ['destroy']]);
  }
  /**
   * Display a listing of the resource.
   */
  public function index()
  {
    $users = (new User)->newQuery();
    if (request()->has('search')) {
      $users->where('name', 'Like', '%' . request()->input('search') . '%');
    }
    $users->latest();
    $users = $users->paginate(5);
    return view('admin.user.index', compact('users'))->with('i', (request()->input('page', 1) - 1) * 5);
  }
  /**
   * Show the form for creating a new resource.
   */
  public function create()
  {
    $roles = Role::all();
    return view('admin.user.create', compact('roles'));
  }
  /**
   * Store a newly created resource in storage.
   */
  public function store(Request $request)
  {
    $request->validate([
      'name' => ['required', 'string', 'max:255'],
      'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
      'password' => ['required', 'confirmed'],
    ]);
    $user = User::create([
      'name' => $request->name,
      'email' => $request->email,
      'password' => Hash::make($request->password),
    ]);
    if (!empty($request->roles)) {
      $user->assignRole($request->roles);
    }
    return redirect()->route('admin.user.index')->with('message', 'User created successfully.');
  }
  /**
   * Display the specified resource.
   */
  public function show(User $user)
  {
    $roles = Role::all();
    $userHasRoles = array_column(json_decode($user->roles, true), 'id');
    return view('admin.user.show', compact('user', 'roles', 'userHasRoles'));
  }
  /**
   * Show the form for editing the specified resource.
   */
  public function edit(User $user)
  {
    $roles = Role::all();
    $userHasRoles = array_column(json_decode($user->roles, true), 'id');
    return view('admin.user.edit', compact('user', 'roles', 'userHasRoles'));
  }
  /**
   * Update the specified resource in storage.
   */
  public function update(Request $request, User $user)
  {
    $request->validate([
      'name' => ['required', 'string', 'max:255'],
      'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email,' . $user->id],
      'password' => ['nullable', 'confirmed'],
    ]);
    $user->update([
      'name' => $request->name,
      'email' => $request->email,
    ]);
    if ($request->password) {
      $user->update([
        'password' => Hash::make($request->password),
      ]);
    }
    $roles = $request->roles ?? [];
    $user->syncRoles($roles);
    return redirect()->route('admin.user.index')->with('message', 'User updated successfully.');
  }
  /**
   * Remove the specified resource from storage.
   */
  public function destroy(User $user)
  {
    $user->delete();
    return redirect()->route('admin.user.index')->with('message', 'User deleted successfully');
  }
}

C:\xampp82\htdocs\lva3\app\Http\Controllers\Admin\RoleController.php

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class RoleController extends Controller
{
  public function __construct()
  {
    $this->middleware('can:role list', ['only' => ['index', 'show']]);
    $this->middleware('can:role create', ['only' => ['create', 'store']]);
    $this->middleware('can:role edit', ['only' => ['update', 'edit']]);
    $this->middleware('can:role delete', ['only' => ['delete']]);
  }
  /**
   * Display a listing of the resource.
   */
  public function index()
  {
    $roles = (new Role())->newQuery();
    if (request()->has('search')) {
      $roles->where('name', 'Like', '%' . request()->input('search') . '%');
    }
    $roles->latest();
    $roles = $roles->paginate(5);
    return view('admin.role.index', compact('roles'))->with('i', (request()->input('page', 1) - 1) * 5);
  }
  /**
   * Show the form for creating a new resource.
   */
  public function create()
  {
    $permissions = Permission::all();
    return view('admin.role.create', compact('permissions'));
  }
  /**
   * Store a newly created resource in storage.
   */
  public function store(Request $request)
  {
    $request->validate(['name' => 'required|string|max:255|unique:' . config('permission.table_names.roles', 'roles') . ',name']);
    $role = Role::create(['name' => $request->name, 'guard_name' => 'web']);
    if (!empty($request->permissions)) {
      $role->givePermissionTo($request->permissions);
    }
    return redirect()->route('admin.role.index')->with('message', 'Role created successfully.');
  }
  /**
   * Display the specified resource.
   */
  public function show(Role $role)
  {
    $permissions = Permission::all();
    $roleHasPermissions = array_column(json_decode($role->permissions, true), 'id');
    return view('admin.role.show', compact('role', 'permissions', 'roleHasPermissions'));
  }
  /**
   * Show the form for editing the specified resource.
   */
  public function edit(Role $role)
  {
    $permissions = Permission::all();
    $roleHasPermissions = array_column(json_decode($role->permissions, true), 'id');
    return view('admin.role.edit', compact('role', 'permissions', 'roleHasPermissions'));
  }
  /**
   * Update the specified resource in storage.
   */
  public function update(Request $request, Role $role)
  {
    $request->validate(['name' => 'required|string|max:255|unique:' . config('permission.table_names.roles', 'roles') . ',name,' . $role->id]);
    $role->update(['name' => $request->name, 'guard_name' => 'web']);
    $permissions = $request->permissions ?? [];
    $role->syncPermissions($permissions);
    return redirect()->route('admin.role.index')->with('message', 'Role updated successfully.');
  }
  /**
   * Remove the specified resource from storage.
   */
  public function destroy(Role $role)
  {
    $role->delete();
    return redirect()->route('admin.role.index')->with('message', 'Role deleted successfully');
  }
}

C:\xampp82\htdocs\lva3\app\Http\Controllers\Admin\PermissionController.php

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Spatie\Permission\Models\Permission;
class PermissionController extends Controller
{
    public function __construct()
    {
      $this->middleware('can:permission list', ['only' => ['index', 'show']]);
      $this->middleware('can:permission create', ['only' => ['create', 'store']]);
      $this->middleware('can:permission edit', ['only' => ['edit', 'update']]);
      $this->middleware('can:permission delete', ['only' => ['destroy']]);
    }
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
      $permissions = (new Permission())->newQuery();
      if (request()->has('search')) {
        $permissions->where('name', 'Like', '%' . request()->input('search') . '%');
      }
      $permissions->latest();
      $permissions = $permissions->paginate(5);
      return view('admin.permission.index', compact('permissions'))->with('i', (request()->input('page', 1) - 1) * 5);
    }
    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
      return view('admin.permission.create');
    }
    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
      $request->validate(['name' => 'required|string|max:255|unique:' . config('permission.table_names.permissions', 'permissions') . ',name']);
      Permission::create(['name' => $request->name, 'guard_name' => 'web']);
      return redirect()->route('admin.permission.index')->with('message', 'Permission created successfully.');
    }
    /**
     * Display the specified resource.
     */
    public function show(Permission $permission)
    {
      return view('admin.permission.show', compact('permission'));
    }
    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Permission $permission)
    {
      return view('admin.permission.edit', compact('permission'));
    }
    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Permission $permission)
    {
      $request->validate(['name' => 'required|string|max:255|unique:' . config('permission.table_names.permissions', 'permissions') . ',name,' . $permission->id,]);
      $permission->update(['name' => $request->name, 'guard_name' => 'web']);
      return redirect()->route('admin.permission.index')->with('message', 'Permission updated successfully.');
    }
    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Permission $permission)
    {
      $permission->delete();
      return redirect()->route('admin.permission.index')->with('message', 'Permission deleted successfully');
    }
}

C:\xampp82\htdocs\lva3\app\Models\User.php

<?php

namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
  use HasApiTokens, HasFactory, Notifiable, HasRoles;
  /**
   * The attributes that are mass assignable.
   *
   * @var array<int, string>
   */
  protected $fillable = [
    'name',
    'email',
    'password',
  ];
  /**
   * The attributes that should be hidden for serialization.
   *
   * @var array<int, string>
   */
  protected $hidden = [
    'password',
    'remember_token',
  ];
  /**
   * The attributes that should be cast.
   *
   * @var array<string, string>
   */
  protected $casts = [
    'email_verified_at' => 'datetime',
  ];
}

C:\xampp82\htdocs\lva3\app\Providers\AppServiceProvider.php

<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Pagination\Paginator;
class AppServiceProvider extends ServiceProvider
{
  /**
   * Register any application services.
   */
  public function register(): void
  {
    //
  }
  /**
   * Bootstrap any application services.
   */
  public function boot(): void
  {
    Paginator::useBootstrap();
  }
}

C:\xampp82\htdocs\lva3\app\View\Components\Layout.php

<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class Layout extends Component
{
  /**
   * Create a new component instance.
   */
  public function __construct()
  {
    //
  }
  /**
   * Get the view / contents that represent the component.
   */
  public function render(): View|Closure|string
  {
    return view('components.layout');
  }
}

C:\xampp82\htdocs\lva3\config\app.php

/*
        * Dev Customer Service Providers...
        */
    Spatie\Permission\PermissionServiceProvider::class,

C:\xampp82\htdocs\lva3\config\permission.php

<?php
return [
  'models' => [
    /*
         * When using the "HasPermissions" trait from this package, we need to know which
         * Eloquent model should be used to retrieve your permissions. Of course, it
         * is often just the "Permission" model but you may use whatever you like.
         *
         * The model you want to use as a Permission model needs to implement the
         * `Spatie\Permission\Contracts\Permission` contract.
         */
    'permission' => Spatie\Permission\Models\Permission::class,
    /*
         * When using the "HasRoles" trait from this package, we need to know which
         * Eloquent model should be used to retrieve your roles. Of course, it
         * is often just the "Role" model but you may use whatever you like.
         *
         * The model you want to use as a Role model needs to implement the
         * `Spatie\Permission\Contracts\Role` contract.
         */
    'role' => Spatie\Permission\Models\Role::class,
  ],
  'table_names' => [
    /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your roles. We have chosen a basic
         * default value but you may easily change it to any table you like.
         */
    'roles' => 'roles',
    /*
         * When using the "HasPermissions" trait from this package, we need to know which
         * table should be used to retrieve your permissions. We have chosen a basic
         * default value but you may easily change it to any table you like.
         */
    'permissions' => 'permissions',
    /*
         * When using the "HasPermissions" trait from this package, we need to know which
         * table should be used to retrieve your models permissions. We have chosen a
         * basic default value but you may easily change it to any table you like.
         */
    'model_has_permissions' => 'model_has_permissions',
    /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your models roles. We have chosen a
         * basic default value but you may easily change it to any table you like.
         */
    'model_has_roles' => 'model_has_roles',
    /*
         * When using the "HasRoles" trait from this package, we need to know which
         * table should be used to retrieve your roles permissions. We have chosen a
         * basic default value but you may easily change it to any table you like.
         */
    'role_has_permissions' => 'role_has_permissions',
  ],
  'column_names' => [
    /*
         * Change this if you want to name the related pivots other than defaults
         */
    'role_pivot_key' => null, //default 'role_id',
    'permission_pivot_key' => null, //default 'permission_id',
    /*
         * Change this if you want to name the related model primary key other than
         * `model_id`.
         *
         * For example, this would be nice if your primary keys are all UUIDs. In
         * that case, name this `model_uuid`.
         */
    'model_morph_key' => 'model_id',
    /*
         * Change this if you want to use the teams feature and your related model's
         * foreign key is other than `team_id`.
         */
    'team_foreign_key' => 'team_id',
  ],
  /*
     * When set to true, the method for checking permissions will be registered on the gate.
     * Set this to false, if you want to implement custom logic for checking permissions.
     */
  'register_permission_check_method' => true,
  /*
     * When set to true the package implements teams using the 'team_foreign_key'. If you want
     * the migrations to register the 'team_foreign_key', you must set this to true
     * before doing the migration. If you already did the migration then you must make a new
     * migration to also add 'team_foreign_key' to 'roles', 'model_has_roles', and
     * 'model_has_permissions'(view the latest version of package's migration file)
     */
  'teams' => false,
  /*
     * When set to true, the required permission names are added to the exception
     * message. This could be considered an information leak in some contexts, so
     * the default setting is false here for optimum safety.
     */
  'display_permission_in_exception' => false,
  /*
     * When set to true, the required role names are added to the exception
     * message. This could be considered an information leak in some contexts, so
     * the default setting is false here for optimum safety.
     */
  'display_role_in_exception' => false,
  /*
     * By default wildcard permission lookups are disabled.
     */
  'enable_wildcard_permission' => false,
  'cache' => [
    /*
         * By default all permissions are cached for 24 hours to speed up performance.
         * When permissions or roles are updated the cache is flushed automatically.
         */
    'expiration_time' => \DateInterval::createFromDateString('24 hours'),
    /*
         * The cache key used to store all permissions.
         */
    'key' => 'spatie.permission.cache',
    /*
         * You may optionally indicate a specific cache driver to use for permission and
         * role caching using any of the `store` drivers listed in the cache.php config
         * file. Using 'default' here means to use the `default` set in cache.php.
         */
    'store' => 'default',
  ],
];

C:\xampp82\htdocs\lva3\database\migrations\2014_10_12_000000_create_users_table.php

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
  /**
   * Run the migrations.
   */
  public function up(): void
  {
    Schema::create('users', function (Blueprint $table) {
      $table->id();
      $table->string('name');
      $table->string('email')->unique();
      $table->timestamp('email_verified_at')->nullable();
      $table->string('password');
      $table->rememberToken();
      $table->timestamps();
    });
  }
  /**
   * Reverse the migrations.
   */
  public function down(): void
  {
    Schema::dropIfExists('users');
  }
};

C:\xampp82\htdocs\lva3\database\migrations\2023_10_06_062030_create_permission_tables.php

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Spatie\Permission\PermissionRegistrar;
class CreatePermissionTables extends Migration
{
  /**
   * Run the migrations.
   *
   * @return void
   */
  public function up()
  {
    $tableNames = config('permission.table_names');
    $columnNames = config('permission.column_names');
    $teams = config('permission.teams');
    if (empty($tableNames)) {
      throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
    }
    if ($teams && empty($columnNames['team_foreign_key'] ?? null)) {
      throw new \Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
    }
    Schema::create($tableNames['permissions'], function (Blueprint $table) {
      $table->bigIncrements('id'); // permission id
      $table->string('name');       // For MySQL 8.0 use string('name', 125);
      $table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
      $table->timestamps();
      $table->unique(['name', 'guard_name']);
    });
    Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
      $table->bigIncrements('id'); // role id
      if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
        $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
        $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
      }
      $table->string('name');       // For MySQL 8.0 use string('name', 125);
      $table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125);
      $table->timestamps();
      if ($teams || config('permission.testing')) {
        $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
      } else {
        $table->unique(['name', 'guard_name']);
      }
    });
    Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) {
      $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
      $table->string('model_type');
      $table->unsignedBigInteger($columnNames['model_morph_key']);
      $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
      $table->foreign(PermissionRegistrar::$pivotPermission)
        ->references('id') // permission id
        ->on($tableNames['permissions'])
        ->onDelete('cascade');
      if ($teams) {
        $table->unsignedBigInteger($columnNames['team_foreign_key']);
        $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
        $table->primary(
          [$columnNames['team_foreign_key'], PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
          'model_has_permissions_permission_model_type_primary'
        );
      } else {
        $table->primary(
          [PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
          'model_has_permissions_permission_model_type_primary'
        );
      }
    });
    Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) {
      $table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
      $table->string('model_type');
      $table->unsignedBigInteger($columnNames['model_morph_key']);
      $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
      $table->foreign(PermissionRegistrar::$pivotRole)
        ->references('id') // role id
        ->on($tableNames['roles'])
        ->onDelete('cascade');
      if ($teams) {
        $table->unsignedBigInteger($columnNames['team_foreign_key']);
        $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
        $table->primary(
          [$columnNames['team_foreign_key'], PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'],
          'model_has_roles_role_model_type_primary'
        );
      } else {
        $table->primary(
          [PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'],
          'model_has_roles_role_model_type_primary'
        );
      }
    });
    Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) {
      $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
      $table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
      $table->foreign(PermissionRegistrar::$pivotPermission)
        ->references('id') // permission id
        ->on($tableNames['permissions'])
        ->onDelete('cascade');
      $table->foreign(PermissionRegistrar::$pivotRole)
        ->references('id') // role id
        ->on($tableNames['roles'])
        ->onDelete('cascade');
      $table->primary([PermissionRegistrar::$pivotPermission, PermissionRegistrar::$pivotRole], 'role_has_permissions_permission_id_role_id_primary');
    });
    app('cache')
      ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
      ->forget(config('permission.cache.key'));
  }
  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    $tableNames = config('permission.table_names');
    if (empty($tableNames)) {
      throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
    }
    Schema::drop($tableNames['role_has_permissions']);
    Schema::drop($tableNames['model_has_roles']);
    Schema::drop($tableNames['model_has_permissions']);
    Schema::drop($tableNames['roles']);
    Schema::drop($tableNames['permissions']);
  }
}

C:\xampp82\htdocs\lva3\database\seeders\BasicPermissionSeeder.php

<?php
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class BasicPermissionSeeder extends Seeder
{
  /**
   * Run the database seeds.
   */
  public function run(): void
  {
    $permissions = [
      'permission list',
      'permission create',
      'permission edit',
      'permission delete',
      'role list',
      'role create',
      'role edit',
      'role delete',
      'user list',
      'user create',
      'user edit',
      'user delete'
    ];
    foreach ($permissions as $permission) :
      Permission::create(['name' => $permission]);
    endforeach;
    $role1 = Role::create(['name' => 'subscriber']);
    $role1->givePermissionTo(['permission list', 'role list', 'user list']);
    $role2 = Role::create(['name' => 'admin']);
    $role2->givePermissionTo(['permission list', 'role list', 'user list', 'permission edit', 'role edit', 'user edit']);
    $role3 = Role::create(['name' => 'super-admin']);
    $role3->givePermissionTo($permissions);
    $user1 = User::factory()->create([
      'name' => 'Subscriber',
      'email' => 'subscriber@test.com',
    ]);
    $user1->assignRole($role1);
    $user2 = User::factory()->create([
      'name' => 'Admin',
      'email' => 'admin@test.com',
    ]);
    $user2->assignRole($role1);
    $user2->assignRole($role2);
    $user3 = User::factory()->create([
      'name' => 'Super Admin',
      'email' => 'superadmin@test.com',
    ]);
    $user3->assignRole($role1);
    $user3->assignRole($role2);
    $user3->assignRole($role3);
  }
}

C:\xampp82\htdocs\lva3\database\seeders\DatabaseSeeder.php

<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
  /**
   * Seed the application's database.
   */
  public function run(): void
  {
    $this->call([
      BasicPermissionSeeder::class
    ]);
  }
}

View

C:\xampp82\htdocs\lva3\resources\views\admin\permission\create.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Permissions') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="py-12 container">
    <div class="d-flex  align-items-center">
      <h1>{{ __('Create permission') }}</h1>
      <a href="{{route('admin.permission.index')}}" class="btn btn-primary ms-2">{{ __('Back to all permissions')}}</a>
      @if ($errors->any())
      <ul class="mt-3 list-none list-inside text-sm text-red-400">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
      </ul>
      @endif
    </div>
    <div class="w-50">
      <div class="w-50">
        <form method="POST" action="{{ route('admin.permission.store') }}">
          @csrf
          <div class="py-2">
            <label class="mb-2" for="name">{{__('Name') }}</label>
            <input id="name" class="form-control" type="text" name="name" value="{{ old('name') }}" />
          </div>
          <div class="mt-4">
            <button type='submit' class='btn btn-primary'>{{ __('Create') }}</button>
          </div>
        </form>
      </div>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\permission\edit.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Permissions') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="container">
    <div class="d-flex  align-items-center">
      <h1 class="inline-block">{{ __('Update permission') }}</h1>
      <a href="{{route('admin.permission.index')}}" class="btn btn-primary text-white ms-2">{{ __('Back to all permissions')}}</a>
      @if ($errors->any())
      <ul class="mt-3 list-none list-inside text-sm text-red-400">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
      </ul>
      @endif
    </div>
    <div class="w-50 px-3 py-2 bg-white overflow-hidden">
      <form method="POST" action="{{ route('admin.permission.update', $permission->id) }}">
        @csrf
        @method('PUT')
        <div class="py-2">
          <label class="mb-2" for="name">{{__('Name') }}</label>
          <input id="name" class="form-control" type="text" name="name" value="{{ old('name', $permission->name) }}" />
        </div>
        <div class="flex justify-end mt-4">
          <button type='submit' class='btn btn-primary rounded-md text-white uppercase'>{{__('Update')}}</button>
        </div>
      </form>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\permission\index.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Permissions') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="py-12 container">
    @can('permission create')
    <div class="mb-2">
      <a href="{{ route('admin.permission.create') }}" class="btn btn-primary text-white text-center">{{__('Add Permission') }}</a>
    </div>
    @endcan
    <div class="py-2">
      @if(session()->has('message'))
      <div class="mb-4 font-bold">
        {{ session()->get('message') }}
      </div>
      @endif
      <div class="container">
        <div class="row">
          <div class="col-md-4 p-0">
            <form method="GET" class="d-flex" action="{{ route('admin.permission.index') }}">
              <input type="search" name="search" value="{{ request()->input('search') }}" class="form-control"
                placeholder="Search">
              <button type='submit' class='btn btn-success mx-2'>{{ __('Search') }}</button>
            </form>
          </div>
        </div>
      </div>
      <table class="border-collapse table">
        <thead>
          <tr>
            <th>{{ __('Name') }}</th>
            @canany(['permission edit', 'permission delete'])
            <th>{{ __('Actions') }}</th>
            @endcanany
          </tr>
        </thead>
        <tbody class="bg-white">
          @foreach($permissions as $permission)
          <tr>
            <td>
              <a href="{{route('admin.permission.show', $permission->id)}}" class="text-decoration-none">{{
                $permission->name}}</a>
            </td>
            @canany(['permission edit', 'permission delete'])
            <td>
              <form action="{{ route('admin.permission.destroy', $permission->id) }}" method="POST">
                <a href="{{route('admin.permission.edit', $permission->id)}}" class="btn btn-primary text-white mr-4">{{ __('Edit')
                  }}</a>
                @can('permission delete')
                @csrf
                @method('DELETE')
                <button class="btn btn-danger text-white">{{ __('Delete') }}</button>
                @endcan
              </form>
            </td>
            @endcanany
          </tr>
          @endforeach
        </tbody>
      </table>
    </div>
    <div class="py-8">
      {{ $permissions->appends(request()->query())->links() }}
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\permission\show.blade.php

<x-layout>
  <x-slot name="header">
    <h2 class="font-bold">{{ __('Permissions') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="py-12 container">
    <div class="d-flex  align-items-center">
      <h1 class="inline-block">{{ __('View user') }}</h1>
      <a href="{{route('admin.permission.index')}}" class="btn btn-primary text-white ms-2">{{ __('Back to all
        users')}}</a>
      @if ($errors->any())
      <ul class="mt-3 list-none list-inside text-sm text-red-400">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
      </ul>
      @endif
    </div>
    <div class="w-50 px-3 py-2">
      <table class="border-collapse table">
        <tbody class="bg-white">
          <tr>
            <td></td>
            <td>{{$permission->name}}</td>
          </tr>
          <tr>
            <td>{{ __('Created') }}</td>
            <td>{{$permission->created_at}}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\role\create.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Roles') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="py-12 container">
    <div class="d-flex  align-items-center">
      <h1>{{ __('Create role') }}</h1>
      <a href="{{route('admin.role.index')}}" class="btn btn-primary ms-2">{{ __('Back to all roles')}}</a>
      @if ($errors->any())
      <ul class="mt-3 list-none list-inside text-sm text-red-400">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
      </ul>
      @endif
    </div>
    <div class="w-50">
      <form method="POST" action="{{ route('admin.role.store') }}">
        @csrf
        @method("POST")
        <div class="py-2">
          <label class="mb-2" for="name">{{__('Name') }}</label>
          <input id="name" class="form-control" type="text" name="name" value="{{ old('name') }}" />
        </div>
        <div class="py-2">
          <h3>Permissions</h3>
          <div class="grid grid-cols-4 gap-4">
            @forelse ($permissions as $permission)
            <div class="col-span-4">
              <label class="form-check-label">
                <input type="checkbox" name="permissions[]" value="{{ $permission->name }}">
                <span class="ms-1">{{ $permission->name }}</span>
              </label>
            </div>
            @empty
            ----
            @endforelse
          </div>
        </div>
        <div class="mt-4">
          <button type='submit' class='btn btn-primary'>{{ __('Create') }}</button>
        </div>
      </form>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\role\edit.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Roles') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="container">
    <div class="d-flex  align-items-center">
      <h1 class="inline-block">{{ __('Update user') }}</h1>
      <a href="{{route('admin.role.index')}}" class="btn btn-primary text-white ms-2">{{ __('Back to all users')}}</a>
      @if ($errors->any())
      <ul class="mt-3 list-none list-inside text-sm text-red-400">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
      </ul>
      @endif
    </div>
    <div class="w-50 px-3 py-2 bg-white overflow-hidden">
      <form method="POST" action="{{ route('admin.role.update', $role->id) }}">
        @csrf
        @method('PUT')
        <div class="py-2">
          <label class="mb-2" for="name">{{__('Name') }}</label>
          <input id="name" class="form-control" type="text" name="name" value="{{ old('name', $role->name) }}" />
        </div>
        @unless ($role->name == env('APP_SUPER_ADMIN', 'super-admin'))
        <div class="py-2">
          <h3>Permissions</h3>
          <div class="grid grid-cols-4 gap-4">
            @forelse ($permissions as $permission)
            <label class="form-check-label">
              <input type="checkbox" name="permissions[]" value="{{ $permission->name }}" {{ in_array($permission->id,
              $roleHasPermissions) ? 'checked' : '' }} class="rounded shadow-sm">
              {{ $permission->name }}
            </label>
            @empty
            ----
            @endforelse
          </div>
          @endunless
          <div class="flex justify-end mt-4">
            <button type='submit' class='btn btn-primary rounded-md text-white uppercase'>{{__('Update')}}</button>
          </div>
      </form>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\role\index.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Roles') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="py-12 container">
    @can('role create')
    <div class="mb-2">
      <a href="{{ route('admin.role.create') }}" class="btn btn-primary text-white text-center">{{__('Add Role') }}</a>
    </div>
    @endcan
    <div class="py-2">
      @if(session()->has('message'))
      <div class="mb-4 font-bold">
        {{ session()->get('message') }}
      </div>
      @endif
      <div class="container">
        <div class="row">
          <div class="col-md-4 p-0">
            <form method="GET" class="d-flex" action="{{ route('admin.user.index') }}">
              <input type="search" name="search" value="{{ request()->input('search') }}" class="form-control"
                placeholder="Search">
              <button type='submit' class='btn btn-success mx-2'>{{ __('Search') }}</button>
            </form>
          </div>
        </div>
      </div>
      <table class="border-collapse table">
        <thead>
          <tr>
            <th>{{ __('Roles') }}</th>
            @canany(['role edit', 'role delete'])
            <th>{{ __('Actions') }}</th>
            @endcanany
          </tr>
        </thead>
        <tbody class="bg-white">
          @foreach($roles as $role)
          <tr>
            <td><a href="{{route('admin.role.show', $role->id)}}" class="text-decoration-none">{{ $role->name }}</a>
            </td>
            @canany(['role edit', 'role delete'])
            <td>
              <form action="{{ route('admin.role.destroy', $role->id) }}" method="POST">
                @can('role edit')
                <a href="{{route('admin.role.edit', $role->id)}}"
                  class="btn btn-primary text-white mr-4">{{__('Edit')}}</a>
                @endcan
                @can('role delete')
                @csrf
                @method('DELETE')
                <button class="btn btn-danger text-white">{{ __('Delete') }}</button>
                @endcan
              </form>
            </td>
            @endcanany
          </tr>
          @endforeach
        </tbody>
      </table>
    </div>
    <div class="py-8">
      {{ $roles->appends(request()->query())->links() }}
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\role\show.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Users') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="py-12 container">
    <div class="d-flex  align-items-center">
      <h1 class="inline-block">{{ __('View user') }}</h1>
      <a href="{{route('admin.role.index')}}" class="btn btn-primary text-white ms-2">{{ __('Back to all users')}}</a>
      @if ($errors->any())
      <ul class="mt-3 list-none list-inside text-sm text-red-400">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
      </ul>
      @endif
    </div>
    <div class="w-50 px-3 py-2">
      <table class="border-collapse table">
        <tbody>
          <tr>
            <td></td>
            <td>{{$role->name}}</td>
          </tr>
          @unless ($role->name == env('APP_SUPER_ADMIN', 'super-admin'))
          <tr>
            <td>{{ __('Permissions') }}</td>
            <td>
              <div class="grid grid-cols-4 gap-4">
                @forelse ($permissions as $permission)
                <div class="col-span-4 sm:col-span-2 md:col-span-2">
                  <label class="form-check-label">
                    <input type="checkbox" name="permissions[]" value="{{ $permission->name }}"
                      {{in_array($permission->id, $roleHasPermissions) ? 'checked' : '' }} disabled="disabled"
                    class="rounded"><span class="ms-1">{{ $permission->name }}</span>
                  </label>
                </div>
                @empty
                ----
                @endforelse
              </div>
            </td>
          </tr>
          @endunless
        </tbody>
      </table>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\user\create.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Users') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="py-12 container">
    <div class="flex justify-between items-center">
      <h1>{{ __('Create user') }}</h1>
      <a href="{{route('admin.user.index')}}" class="btn btn-primary ms-2">{{ __('Back to all users')}}</a>
      @if ($errors->any())
      <ul class="mt-3 list-none list-inside text-sm text-red-400">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
      </ul>
      @endif
    </div>
    <div class="w-50">
      <form method="POST" action="{{ route('admin.user.store') }}">
        @csrf
        @method("POST")
        <div class="py-2">
          <label class="mb-2" for="name">{{__('Name') }}</label>
          <input id="name" class="form-control" type="text" name="name" value="{{ old('name') }}" />
        </div>
        <div class="py-2">
          <label class="mb-2" for="email">{{__('Email') }}</label>
          <input id="email" class="form-control" type="email" name="email" value="{{ old('email') }}" />
        </div>
        <div class="py-2">
          <label class="mb-2" for="password">{{__('Password') }}</label>
          <input id="password" class="form-control" type="password" name="password" />
        </div>
        <div class="py-2">
          <label class="mb-2" for="password_confirmation">{{__('Password Confirmation') }}</label>
          <input id="password_confirmation" class="form-control" type="password" name="password_confirmation" />
        </div>
        <div class="py-2">
          <h3>Roles</h3>
          <div class="grid grid-cols-4 gap-4">
            @forelse ($roles as $role)
            <div class="col-span-4">
              <label class="form-check-label">
                <input type="checkbox" name="roles[]" value="{{ $role->name }}"><span class="ms-1">{{ $role->name
                  }}</span>
              </label>
            </div>
            @empty
            ----
            @endforelse
          </div>
        </div>
        <div class="mt-4">
          <button type='submit' class='btn btn-primary'>{{ __('Create') }}</button>
        </div>
      </form>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\user\edit.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Users') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="container">
    <div class="d-flex  align-items-center">
      <h1 class="inline-block">{{ __('Update user') }}</h1>
      <a href="{{route('admin.user.index')}}" class="btn btn-primary text-white ms-2">{{ __('Back to all users')}}</a>
      @if ($errors->any())
      <ul class="mt-3 list-none list-inside text-sm text-red-400">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
      </ul>
      @endif
    </div>
    <div class="w-50 px-3 py-2 bg-white overflow-hidden">
      <form method="POST" action="{{ route('admin.user.update', $user->id) }}">
        @csrf
        @method('PUT')
        <div class="py-2">
          <label class="mb-2" for="name">{{__('Name') }}</label>
          <input id="name" class="form-control rounded-md shadow-sm" type="text" name="name"
            value="{{ old('name', $user->name) }}" />
        </div>
        <div class="py-2">
          <label class="mb-2" for="email">{{__('Email') }}</label>
          <input id="email" class="form-control rounded-md shadow-sm" type="email" name="email"
            value="{{ old('email', $user->email) }}" />
        </div>
        <div class="py-2">
          <label class="mb-2" for="password">{{__('Password') }}</label>
          <input id="password" class="form-control rounded-md shadow-sm" type="password" name="password" />
        </div>
        <div class="py-2">
          <label class="mb-2" for="password_confirmation">{{__('Password Confirmation') }}</label>
          <input id="password_confirmation" class="form-control rounded-md shadow-sm" type="password"
            name="password_confirmation" />
        </div>
        <div class="py-2">
          <h3>Roles</h3>
          <div class="grid grid-cols-4 gap-4">
            @forelse ($roles as $role)
            <div class="col-span-4 sm:col-span-2 md:col-span-1">
              <label class="form-check-label">
                <input type="checkbox" name="roles[]" value="{{ $role->name }}" {{ in_array($role->id, $userHasRoles) ?
                'checked' : '' }} class="rounded shadow-sm"><span class="ms-1">{{ $role->name }}</span>
              </label>
            </div>
            @empty
            ----
            @endforelse
          </div>
        </div>
        <div class="flex justify-end mt-4">
          <button type='submit' class='btn btn-primary rounded-md text-white uppercase'>{{__('Update')}}</button>
        </div>
      </form>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\user\index.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Users') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="py-12 container">
    <div class="mx-auto">
      <div class="bg-white overflow-hidden shadow">
        <div class="p-5 bg-white">
          <div class="flex flex-col mt-8">
            @can('user create')
            <div class="mb-2">
              <a href="{{ route('admin.user.create') }}" class="btn btn-primary text-white text-center">{{__('Add User')
                }}</a>
            </div>
            @endcan
            <div class="py-2">
              @if(session()->has('message'))
              <div class="mb-4 font-bold">
                {{ session()->get('message') }}
              </div>
              @endif
              <div class="container">
                <div class="row">
                  <div class="col-md-4 p-0">
                    <form method="GET" class="d-flex" action="{{ route('admin.user.index') }}">
                      <input type="search" name="search" value="{{ request()->input('search') }}" class="form-control"
                        placeholder="Search">
                      <button type='submit' class='btn btn-success mx-2'>{{ __('Search') }}</button>
                    </form>
                  </div>
                </div>
              </div>
              <table class="border-collapse table">
                <thead>
                  <tr>
                    <th class="py-4  font-bold uppercase text-left">{{ __('Name')}}</th>
                    <th class="py-4  font-bold uppercase text-left">{{ __('Email')}}</th>
                    @canany(['user edit', 'user delete'])
                    <th class="py-4  font-bold uppercase text-left">{{ __('Actions') }}</th>
                    @endcanany
                  </tr>
                </thead>
                <tbody class="bg-white">
                  @foreach($users as $user)
                  <tr>
                    <td>
                      <div class="text-sm text-gray-900">
                        <a href="{{route('admin.user.show', $user->id)}}" class="text-decoration-none">{{
                          $user->name}}</a>
                      </div>
                    </td>
                    <td>
                      <div class="text-sm text-gray-900">
                        {{ $user->email }}
                      </div>
                    </td>
                    <td>
                      @canany(['user edit', 'user delete'])
                      <form action="{{ route('admin.user.destroy', $user->id) }}" method="POST">
                        @can('user edit')
                        <a href="{{route('admin.user.edit', $user->id)}}" class="btn btn-primary text-white mr-4">{{
                          __('Edit') }}</a>
                        @endcan
                        @can('user delete')
                        @csrf
                        @method('DELETE')
                        <button class="btn btn-danger text-white">{{ __('Delete') }}</button>
                        @endcan
                      </form>
                      @endcan
                    </td>
                  </tr>
                  @endforeach
                </tbody>
              </table>
            </div>
            <div class="py-8">
              {{ $users->appends(request()->query())->links() }}
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\admin\user\show.blade.php

<x-layout>
  <x-slot name="header">
    <h2>{{ __('Users') }}</h2>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Magnam, non!</p>
  </x-slot>
  <div class="py-12 container">
    <div class="d-flex  align-items-center">
      <h1 class="inline-block">{{ __('View user') }}</h1>
      <a href="{{route('admin.user.index')}}" class="btn btn-primary text-white ms-2">{{ __('Back to all users')}}</a>
      @if ($errors->any())
      <ul class="mt-3 list-none list-inside text-sm text-red-400">
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
      </ul>
      @endif
    </div>
    <div class="w-50 px-3 py-2">
      <table class="border-collapse table">
        <tbody>
          <tr>
            <td class="border-b">{{ __('Name') }}</td>
            <td class="border-b">{{$user->name}}</td>
          </tr>
          <tr>
            <td class="border-b">{{__('Email') }}</td>
            <td class="border-b">{{$user->email}}</td>
          </tr>
          <tr>
            <td class="border-b">{{ __('Roles') }}</td>
            <td class="border-b">
              <div class="grid grid-cols-4 gap-4">
                @forelse ($roles as $role)
                <div class="col-span-4">
                  <label class="form-check-label">
                    <input type="checkbox" name="roles[]" value="{{ $role->name }}" {{ in_array($role->id,
                    $userHasRoles) ? 'checked' : '' }} disabled="disabled" class="rounded"><span
                      class="ms-1">{{$role->name }}</span>
                  </label>
                </div>
                @empty
                ----
                @endforelse
              </div>
            </td>
          </tr>
          <tr>
            <td class="border-b">{{ __('Created') }}</td>
            <td class="border-b">{{$user->created_at}}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</x-layout>

C:\xampp82\htdocs\lva3\resources\views\components\layout.blade.php

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- CSRF Token -->
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <title>{{ config('app.name', 'Laravel') }}</title>
  <!-- Fonts -->
  <link rel="dns-prefetch" href="//fonts.gstatic.com">
  <!-- Scripts -->
  @vite(['resources/sass/app.scss', 'resources/js/app.js'])
</head>
<body>
  <div id="app">
    <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
      <div class="container">
        <a class="navbar-brand" href="{{ url('/') }}">
          {{ config('app.name', 'Laravel') }}
        </a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
          aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <!-- Left Side Of Navbar -->
          <ul class="navbar-nav me-auto">
          </ul>
          <!-- Right Side Of Navbar -->
          <ul class="navbar-nav ms-auto">
            <!-- Authentication Links -->
            @guest
            @if (Route::has('login'))
            <li class="nav-item">
              <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
            </li>
            @endif
            @if (Route::has('register'))
            <li class="nav-item">
              <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
            </li>
            @endif
            @else
            <li class="nav-item dropdown">
              <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
                aria-haspopup="true" aria-expanded="false" v-pre>
                {{ Auth::user()->name }}
              </a>
              <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
                <a class="dropdown-item" href="{{ route('logout') }}" onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                  {{ __('Logout') }}
                </a>
                <form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
                  @csrf
                </form>
              </div>
            </li>
            @endguest
          </ul>
        </div>
      </div>
    </nav>
    <!-- Page Heading -->
    <header class="pt-3">
      <div class="container">
        {{ $header }}
      </div>
    </header>
    <!-- Page Content -->
    <main>
      {{ $slot }}
    </main>
  </div>
</body>
</html>

C:\xampp82\htdocs\lva3\resources\views\layouts\app.blade.php

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- CSRF Token -->
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <title>{{ config('app.name', 'Laravel') }}</title>
  <!-- Fonts -->
  <link rel="dns-prefetch" href="//fonts.gstatic.com">
  <!-- Scripts -->
  @vite(['resources/sass/app.scss', 'resources/js/app.js'])
</head>
<body>
  <div id="app">
    <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
      <div class="container">
        <a class="navbar-brand" href="{{ url('/') }}">{{ config('app.name', 'Laravel') }}</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
          aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <!-- Left Side Of Navbar -->
          <ul class="navbar-nav me-auto">
          </ul>
          <!-- Right Side Of Navbar -->
          <ul class="navbar-nav ms-auto">
            <!-- Authentication Links -->
            @guest
            @if (Route::has('login'))
            <li class="nav-item">
              <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
            </li>
            @endif
            @if (Route::has('register'))
            <li class="nav-item">
              <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
            </li>
            @endif
            @else
            <li class="nav-item dropdown">
              <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
                aria-haspopup="true" aria-expanded="false" v-pre>{{ Auth::user()->name }}</a>
              <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
                <a class="dropdown-item" href="{{ route('logout') }}"
                  onclick="event.preventDefault(); document.getElementById('logout-form').submit();">{{ __('Logout')
                  }}</a>
                <form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
                  @csrf
                </form>
              </div>
            </li>
            @endguest
          </ul>
        </div>
      </div>
    </nav>
    <main class="py-4">
      @yield('content')
    </main>
  </div>
</body>
</html>

C:\xampp82\htdocs\lva3\routes\web.php

<?php

use App\Http\Controllers\Admin\RoleController;
use App\Http\Controllers\Admin\UserController;
use App\Http\Controllers\Admin\PermissionController;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\HomeController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/

Route::get('/', function () {
  return view('welcome');
});
Auth::routes();
Route::get('/home', [HomeController::class, 'index'])->name('home');
Route::prefix('admin')->namespace('App\Http\Controllers\Admin')->middleware(['auth'])->group(function () {
  Route::name('admin.')->group(function () {
    Route::resource('user', UserController::class);
    Route::resource('role', RoleController::class);
    Route::resource('permission', PermissionController::class);
  });
});

C:\xampp82\htdocs\lva3.env

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:y+fh9tge6Hhbl4tW/k1yuytvhdc9y1mYVlzu9appHM4=
APP_DEBUG=true
DEBUGBAR_ENABLED=false
APP_URL=https://lva3.com
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lva3
DB_USERNAME=root
DB_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

Source Code

Part 2: Hoàn thiện thêm menu sử dụng spatie-menu

C:\xampp82\htdocs\lva3\app\Providers\AppServiceProvider.php

<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Pagination\Paginator;
use Spatie\Menu\Laravel\Facades\Menu;
use Spatie\Menu\Laravel\Link;
class AppServiceProvider extends ServiceProvider
{
  /**
   * Register any application services.
   */
  public function register(): void
  {
  }
  /**
   * Bootstrap any application services.
   */
  public function boot(): void
  {
    Paginator::useBootstrap();
    $this->buildSidebarMenu();
  }
  protected function  buildSidebarMenu(): void
  {
    Menu::macro('sidebar', function () {
      return Menu::new()
        ->setWrapperTag('aside')
        ->withoutParentTag()
        ->addClass('dropdown-item bg-white')
        ->addIf(
          optional(auth()->user())->hasRole('super-admin'),
          Menu::new()
            ->addClass('menu-list ps-0')
            ->withoutParentTag()
            ->add(Link::to(route('admin.user.index'), __("admin.user.index"))->addClass('text-decoration-none d-block'))
            ->add(Link::to(route('admin.user.create'), __("admin.user.create"))->addClass('text-decoration-none d-block'))
            ->add(Link::to(route('admin.permission.index'), __("admin.permission.index"))->addClass('text-decoration-none d-block'))
            ->add(Link::to(route('admin.permission.create'), __("admin.permission.create"))->addClass('text-decoration-none d-block'))
            ->setActiveClassOnLink()
            ->setActiveFromRequest()
        );
    });
  }
}

C:\xampp82\htdocs\lva3\resources\views\components\layout.blade.php

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- CSRF Token -->
  <meta name="csrf-token" content="{{ csrf_token() }}">
  <title>{{ config('app.name', 'Laravel') }}</title>
  <!-- Fonts -->
  <link rel="dns-prefetch" href="//fonts.gstatic.com">
  <!-- Scripts -->
  @vite(['resources/sass/app.scss', 'resources/js/app.js'])
</head>
<body>
  <div id="app">
    <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
      <div class="container">
        <a class="navbar-brand" href="{{ url('/') }}">
          {{ config('app.name', 'Laravel') }}
        </a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
          aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <!-- Left Side Of Navbar -->
          <ul class="navbar-nav me-auto">
          </ul>
          <!-- Right Side Of Navbar -->
          <ul class="navbar-nav ms-auto">
            <!-- Authentication Links -->
            @guest
            @if (Route::has('login'))
            <li class="nav-item">
              <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
            </li>
            @endif
            @if (Route::has('register'))
            <li class="nav-item">
              <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
            </li>
            @endif
            @else
            <li class="nav-item dropdown">
              <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
                aria-haspopup="true" aria-expanded="false" v-pre>
                {{ Auth::user()->name }}
              </a>
              <div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
                @yield('sidebar', Menu::sidebar())
                <a class="dropdown-item" href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">{{ __('Logout') }}</a>
                <form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">@csrf</form>
              </div>
            </li>
            @endguest
          </ul>
        </div>
      </div>
    </nav>
    <!-- Page Heading -->
    <header class="pt-3">
      <div class="container">
        {{ $header }}
      </div>
    </header>
    <!-- Page Content -->
    <main>
      {{ $slot }}
    </main>
  </div>
</body>
</html>

C:\xampp82\htdocs\lva3\resources\lang\en\admin.php

<?php
return [
  /*
    |--------------------------------------------------------------------------
    | Authentication Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used during authentication for various
    | messages that we need to display to the user. You are free to modify
    | these language lines according to your application's requirements.
    |
    */
  'user' => [
    'index' => 'User List',
    'create' => 'User Create',
  ],
  'permission' => [
    'index' => 'Permission List',
    'create' => 'Permission Create',
  ],
  'role' => [
    'index' => 'Role List',
    'create' => 'Role Create',
  ],
];

Last updated