STUDI KASUS SISTEM INFORMASI SEKOLAH
Praktikum ini merupakan implementasi pengembangan aplikasi web berbasis framework Laravel 9 dengan studi kasus Sistem Informasi Sekolah (Sisfo). Dalam praktikum ini, mahasiswa melakukan serangkaian tahapan mulai dari pembuatan project Laravel baru, konfigurasi koneksi database MySQL, hingga instalasi fitur autentikasi pengguna menggunakan package laravel/ui yang terintegrasi dengan framework CSS Bootstrap. Proses scaffolding autentikasi yang dilakukan secara otomatis menghasilkan controller, model, view, dan route yang siap digunakan, sehingga mahasiswa dapat memahami alur kerja Laravel dalam membangun sistem autentikasi secara efisien tanpa harus membuat dari nol. Selain autentikasi, praktikum ini juga mencakup implementasi sistem templating menggunakan template SB Admin 2 berbasis Bootstrap sebagai antarmuka utama aplikasi. Mahasiswa mempelajari konsep Blade templating engine Laravel — khususnya penggunaan @extends, @yield, @section, dan @include — untuk membangun layout global yang modular (terdiri dari komponen sidebar, topbar, dan konten utama). Di atas fondasi tersebut, dibangun fitur manajemen pengguna (CRUD) lengkap menggunakan Resource Controller, mencakup operasi Create, Read, Update, dan Delete data user dengan dukungan DataTables untuk tampilan tabel yang interaktif.
IIDasar Teori
IVLangkah Kerja Praktikum
Membuat Project Laravel 9
Project dibuat menggunakan Composer dengan perintah berikut di dalam folder workspace:
composer create-project laravel/laravel=^9.0 laravel-sisfo --prefer-distSetelah selesai, project dijalankan dengan:
php artisan serveKonfigurasi Database
File: .env (di root project)
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_sisfo
DB_USERNAME=root
DB_PASSWORD=Penjelasan: File .env adalah file konfigurasi environment Laravel. Variabel DB_DATABASE menentukan nama database yang akan digunakan. Karena menggunakan XAMPP dengan konfigurasi default, DB_USERNAME diisi root dan DB_PASSWORD dikosongkan.
Instalasi Autentikasi
3.1 — Install Package Laravel/UI
composer require laravel/ui3.2 — Generate Scaffolding Autentikasi dengan Bootstrap
php artisan ui bootstrap --authPenjelasan: Perintah ini melakukan dua hal sekaligus: menginstal scaffolding Bootstrap sebagai frontend framework, dan men-generate seluruh file autentikasi secara otomatis, meliputi: - Controller: LoginController, RegisterController, ForgotPasswordController, ResetPasswordController, VerificationController, ConfirmPasswordController - View: login.blade.php, register.blade.php, verify.blade.php, beserta view reset password - Layout dasar: app.blade.php, home.blade.php
3.3 — Install dan Compile Asset
Penjelasan: Perintah npm install mengunduh seluruh dependensi Node.js yang dibutuhkan Bootstrap. Perintah npm run dev mengkompilasi file-file asset (CSS dan JS) menggunakan Laravel Mix sehingga siap digunakan di browser.
3.4 — php artisan migrate
php artisan migratePenjelasan: Perintah ini menjalankan semua file migration yang ada, membuat tabel-tabel yang dibutuhkan di database: users, password_resets, failed_jobs, dan personal_access_tokens. Jika database belum dibuat, Laravel akan menanyakan apakah ingin dibuat otomatis.
3.5 — Tampilan Halaman Autentikasi
Kustomisasi Tabel Users
Membuat Migration TambahanBuka file migration yang baru dibuat di database/migrations/xxxx_costum_table_users.php, kemudian isi dengan kode berikut: File: database/migrations/xxxx_costum_table_users.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string("username")->unique();
$table->string("level");
$table->enum("status", ["ACTIVE", "INACTIVE"])->default("ACTIVE");
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn("username");
$table->dropColumn("level");
$table->dropColumn("status");
});
}
};Penjelasan kode: - Schema::table('users', ...) — memodifikasi tabel users yang sudah ada (bukan membuat baru) - $table->string("username")->unique() — menambah kolom username bertipe VARCHAR(255) dengan constraint UNIQUE agar tidak ada duplikat - $table->string("level") — menambah kolom level untuk menyimpan peran pengguna dalam format JSON - $table->enum("status", ["ACTIVE", "INACTIVE"])->default("ACTIVE") — menambah kolom status dengan nilai terbatas hanya ACTIVE atau INACTIVE, default ACTIVE - Method down() mendefinisikan operasi rollback: menghapus ketiga kolom tersebut
Jalankan migration:
php artisan migrateSeeding User Admin
File: database/seeders/AdminSeeder.php — buat dengan perintah php artisan make:seeder AdminSeeder
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class AdminSeeder extends Seeder
{
public function run()
{
$admin = new \App\Models\User;
$admin->username = "admin";
$admin->name = "Admin Aplikasi";
$admin->email = "admin@sisfo.com";
$admin->level = json_encode(["ADMIN"]);
$admin->password = \Hash::make("12345678");
$admin->status = "ACTIVE";
$admin->save();
$this->command->info("User Admin berhasil ditambahkan");
}
}Penjelasan kode: - new \App\Models\User — membuat instance model Eloquent User - json_encode(["ADMIN"]) — menyimpan level sebagai JSON string karena satu user bisa memiliki lebih dari satu role - \Hash::make("12345678") — mengenkripsi password menggunakan bcrypt sebelum disimpan ke database, sehingga password tidak tersimpan dalam bentuk plain text - $this->command->info(...) — menampilkan pesan ke terminal saat seeder dijalankan
Jalankan seeder:
php artisan db:seed --class=AdminSeederTemplating dengan SB Admin 2
Template SB Admin 2 diunduh dari https://startbootstrap.com/theme/sb-admin-2, diekstrak, lalu seluruh isinya disalin ke folder public/sbadmin di dalam project Laravel.
6.1 — Kustomisasi Halaman Login
File: resources/views/layouts/app.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Sisfo - Login</title>
<link href="{{asset('sbadmin/vendor/fontawesome-free/css/all.min.css')}}" rel="stylesheet">
<link href="{{asset('sbadmin/css/sb-admin-2.min.css')}}" rel="stylesheet">
</head>
<body class="bg-gradient-primary">
<div class="container">
<div class="row justify-content-center">
<div class="col-xl-6 col-lg-6 col-md-9">
<div class="card o-hidden border-0 shadow-lg my-5">
<div class="card-body p-0">
<div class="row">
<div class="col-lg-12 text-center">
<div class="p-5">
<div class="text-center">
<h1 class="h4 text-gray-900 mb-4">Halaman Login</h1>
</div>
<form class="user" method="POST" action="{{ route('login') }}">
@csrf
<div class="form-group">
<input id="email" type="email"
class="form-control form-control-user @error('email') is-invalid @enderror"
name="email" value="{{ old('email') }}" required autofocus/>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<div class="form-group">
<input id="password" type="password"
class="form-control form-control-user @error('password') is-invalid @enderror"
name="password" required />
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
<button type="submit" class="btn btn-primary btn-user btn-block">
Login
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="{{asset('sbadmin/vendor/jquery/jquery.min.js')}}"></script>
<script src="{{asset('sbadmin/vendor/bootstrap/js/bootstrap.bundle.min.js')}}"></script>
<script src="{{asset('sbadmin/vendor/jquery-easing/jquery.easing.min.js')}}"></script>
<script src="{{asset('sbadmin/js/sb-admin-2.min.js')}}"></script>
</body>
</html>Penjelasan kode: - class="bg-gradient-primary" pada <body> — menerapkan background gradasi biru dari SB Admin 2 - {{asset('sbadmin/...')}} — helper Laravel untuk menghasilkan URL absolut ke file di folder public/sbadmin - {{ route('login') }} — helper Laravel untuk menghasilkan URL berdasarkan nama route, bukan hardcode URL - @csrf — direktif Blade yang menyisipkan hidden input token CSRF untuk keamanan form - @error('email') ... @enderror — direktif Blade untuk menampilkan pesan error validasi pada field tertentu
6.2 — Layout Global (main.blade.php)
File: resources/views/layouts/main.blade.php (buat file baru)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Sisfo - @yield('judul')</title>
<link href="{{asset('sbadmin/vendor/fontawesome-free/css/all.min.css')}}" rel="stylesheet">
<link href="{{asset('sbadmin/css/sb-admin-2.min.css')}}" rel="stylesheet">
<link href="{{ asset('sbadmin/vendor/datatables/dataTables.bootstrap4.min.css') }}" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
</head>
<body id="page-top">
<div id="wrapper">
@include("layouts.sidebar")
<div id="content-wrapper" class="d-flex flex-column">
<div id="content">
@include('layouts.topbar')
<div class="container-fluid">
<h1 class="h3 mb-4 text-gray-800">@yield("judul")</h1>
@yield("konten")
</div>
</div>
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright © Sisfo</span>
</div>
</div>
</footer>
</div>
</div>
<a class="scroll-to-top rounded" href="#page-top">
<i class="fas fa-angle-up"></i>
</a>
<!-- Logout Modal -->
<div class="modal fade" id="logoutModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Yakin akan keluar aplikasi ?</h5>
<button class="close" type="button" data-dismiss="modal">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">Silahkan klik tombol logout untuk keluar aplikasi</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button>
<form action="{{route('logout')}}" method="POST">
@csrf
<button class="btn btn-primary">Logout</button>
</form>
</div>
</div>
</div>
</div>
<script src="{{asset('sbadmin/vendor/jquery/jquery.min.js')}}"></script>
<script src="{{asset('sbadmin/vendor/bootstrap/js/bootstrap.bundle.min.js')}}"></script>
<script src="{{asset('sbadmin/vendor/jquery-easing/jquery.easing.min.js')}}"></script>
<script src="{{asset('sbadmin/js/sb-admin-2.min.js')}}"></script>
<script src="{{ asset('sbadmin/vendor/datatables/jquery.dataTables.min.js') }}"></script>
<script src="{{ asset('sbadmin/vendor/datatables/dataTables.bootstrap4.min.js') }}"></script>
<script src="{{ asset('sbadmin/js/demo/datatables-demo.js') }}"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('.select2-multiple').select2({ placeholder: "Pilih", allowClear: true });
});
</script>
</body>
</html>Penjelasan kode: - @yield('judul') di <title> — slot untuk judul halaman yang diisi tiap child view, sehingga tab browser menampilkan judul yang relevan - @include("layouts.sidebar") dan @include('layouts.topbar') — menyisipkan komponen sidebar dan topbar dari file terpisah, menerapkan prinsip DRY (Don't Repeat Yourself) - @yield("konten") — slot utama tempat konten tiap halaman berbeda disisipkan - Modal logout didefinisikan di layout global agar dapat dipanggil dari topbar di halaman manapun
6.3 — Komponen Sidebar
File: resources/views/layouts/sidebar.blade.php (buat file baru)
<ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="#">
<div class="sidebar-brand-icon rotate-n-15">
<i class="fas fa-laugh-wink"></i>
</div>
<div class="sidebar-brand-text mx-3">Sisfo</div>
</a>
<hr class="sidebar-divider my-0">
<li class="nav-item">
<a class="nav-link" href="#">
<i class="fas fa-fw fa-tachometer-alt"></i>
<span>Dashboard</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ route('users.index') }}">
<i class="fas fa-fw fa-users"></i>
<span>Users</span>
</a>
</li>
<hr class="sidebar-divider d-none d-md-block">
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
</ul>6.4 — Komponen Topbar
File: resources/views/layouts/topbar.blade.php (buat file baru)
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow">
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<ul class="navbar-nav ml-auto">
<div class="topbar-divider d-none d-sm-block"></div>
<li class="nav-item dropdown no-arrow">
@if(\Auth::user())
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="mr-2 d-none d-lg-inline text-gray-600 small">{{ Auth::user()->name }}</span>
<img class="img-profile rounded-circle" src="{{ asset('sbadmin/img/undraw_profile.svg') }}">
</a>
@endif
<div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown">
<a class="dropdown-item" href="#">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i> Profile
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#logoutModal">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i> Logout
</a>
</div>
</li>
</ul>
</nav>Penjelasan kode: - @if(\Auth::user()) — direktif Blade untuk mengecek apakah user sedang login sebelum menampilkan info pengguna - {{ Auth::user()->name }} — menampilkan nama user yang sedang login dari session autentikasi - data-target="#logoutModal" — menghubungkan tombol logout ke modal konfirmasi yang sudah didefinisikan di main.blade.php
6.5 — Penggunaan Layout di Home View
File: resources/views/home.blade.php
@extends('layouts.main')
@section("judul") Dashboard @endsection
@section('konten')
<p>Dashboard</p>
@endsectionPenjelasan kode: - @extends('layouts.main') — mendeklarasikan bahwa view ini mewarisi layout dari main.blade.php. Seluruh struktur HTML layout (sidebar, topbar, footer, script) akan tersedia secara otomatis. - @section('judul') Dashboard @endsection — mengisi slot @yield('judul') di layout dengan teks "Dashboard" - @section('konten') ... @endsection — mengisi slot @yield('konten') dengan konten spesifik halaman ini
Manajemen Users (CRUD)
7.1 — Membuat Resource Controller
php artisan make:controller UserController --resourceFile: routes/web.php — tambahkan baris berikut:
use App\Http\Controllers\UserController;
Route::resource('users', UserController::class);Penjelasan: Route::resource() secara otomatis mendaftarkan 7 route sekaligus yang dipetakan ke method di UserController. Hasilnya dapat dilihat dengan php artisan route:list.
7.2 — CREATE — Tambah User
File: app/Http/Controllers/UserController.php — method create dan store:
public function create()
{
return view('user.create');
}
public function store(Request $request)
{
$user = new \App\Models\User;
$user->name = $request->get('nama');
$user->username = $request->get('username');
$user->email = $request->get('email');
$user->password = \Hash::make($request->get('password'));
$user->level = json_encode($request->get('level'));
$user->status = "ACTIVE";
$user->save();
return redirect()->route('users.index')->with('status', 'User baru berhasil ditambahkan');
}File: resources/views/user/create.blade.php (buat folder user di dalam views):
@extends('layouts.main')
@section("judul") Create User @endsection
@section('konten')
<div class="card shadow mb-4">
<div class="card-header py-3"></div>
<div class="card-body">
<div class="row">
<div class="col-lg-9">
<form method="POST" action="{{ route('users.store') }}">
@csrf
<div class="form-group row">
<label class="col-sm-3 col-form-label">Nama</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="nama">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input type="email" class="form-control" name="email">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Username</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="username">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Password</label>
<div class="col-sm-9">
<input type="password" class="form-control" name="password">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Level</label>
<div class="col-sm-4">
<select class="form-control select2-multiple" name="level[]" multiple="multiple">
<option value="ADMIN">ADMIN</option>
<option value="GURU">GURU</option>
<option value="STAFF">STAFF</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="col-sm-10 text-center">
<button type="reset" class="btn btn-warning btn-sm">Batal</button>
<button type="submit" class="btn btn-primary btn-sm">Simpan</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
@endsectionPenjelasan kode: - Method create() hanya me-return view form tanpa data tambahan - Method store() mengambil data dari request dengan $request->get('nama_field'), membuat instance model User, mengisi propertinya, lalu menyimpan dengan $user->save() - json_encode($request->get('level')) — field level menerima array dari select multiple, kemudian diencode ke JSON string untuk disimpan di satu kolom - redirect()->route('users.index')->with('status', '...') — setelah simpan, redirect ke halaman list sambil membawa flash message di session - name="level[]" pada select — tanda [] memberitahu PHP bahwa field ini mengirim array nilai
7.3 — READ — List Users
File: app/Http/Controllers/UserController.php — method index:
public function index()
{
$users = \App\Models\User::all();
return view('user.index', ['users' => $users]);
}File: resources/views/user/index.blade.php:
@extends('layouts.main')
@section("judul") Users @endsection
@section('konten')
@if(session('status'))
<div class="alert alert-success">{{ session('status') }}</div>
@endif
<p>
<a href="{{ route('users.create') }}" class="btn btn-primary btn-sm">Tambah User</a>
</p>
<div class="card shadow mb-4">
<div class="card-header py-3"></div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Name</th>
<th>Username</th>
<th>Email</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@foreach($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ $user->username }}</td>
<td>{{ $user->email }}</td>
<td>
<a href="{{ route('users.edit', $user->id) }}" class="btn btn-sm btn-success">Edit</a>
<form onsubmit="return confirm('Hapus data user ?')" class="d-inline"
action="{{ route('users.destroy', [$user->id]) }}" method="POST">
@csrf
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="Hapus" class="btn btn-danger btn-sm">
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
@endsectionPenjelasan kode: - User::all() — mengambil semua data dari tabel users menggunakan Eloquent ORM, mengembalikan Collection - @if(session('status')) — menampilkan flash message dari session jika ada (dikirim oleh redirect ->with('status', '...')) - @foreach($users as $user) — iterasi tiap data user untuk ditampilkan sebagai baris tabel - id="dataTable" — atribut yang diperlukan oleh script DataTables untuk menginisialisasi fitur pencarian, sorting, dan pagination otomatis - Tombol Hapus menggunakan form dengan method="POST" dan hidden input _method=DELETE karena HTML form tidak mendukung method DELETE secara native; Laravel menangani ini melalui method spoofing
7.4 — UPDATE — Edit User
File: app/Http/Controllers/UserController.php — method edit dan update:
public function edit($id)
{
$user = \App\Models\User::findOrFail($id);
return view('user.edit', ['user' => $user]);
}
public function update(Request $request, $id)
{
$user = \App\Models\User::findOrFail($id);
$user->name = $request->get('nama');
$user->level = json_encode($request->get('level'));
$user->save();
return redirect()->route('users.index')->with('status', 'User berhasil diubah');
}File: resources/views/user/edit.blade.php:
@extends('layouts.main')
@section("judul") Edit User @endsection
@section('konten')
<div class="card shadow mb-4">
<div class="card-body">
<div class="row">
<div class="col-lg-9">
<form method="POST" action="{{ route('users.update', [$user->id]) }}">
<input type="hidden" name="_method" value="PUT">
@csrf
<div class="form-group row">
<label class="col-sm-3 col-form-label">Nama</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="nama" value="{{ $user->name }}">
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Email</label>
<div class="col-sm-9">
<input type="email" class="form-control" name="email" value="{{ $user->email }}" readonly>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Username</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="username" value="{{ $user->username }}" readonly>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label">Level</label>
<div class="col-sm-4">
<select class="form-control select2-multiple" name="level[]" multiple="multiple">
<option value="ADMIN" {{ in_array("ADMIN", json_decode($user->level)) ? "selected" : "" }}>ADMIN</option>
<option value="GURU" {{ in_array("GURU", json_decode($user->level)) ? "selected" : "" }}>GURU</option>
<option value="STAFF" {{ in_array("STAFF", json_decode($user->level)) ? "selected" : "" }}>STAFF</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="col-sm-10 text-center">
<a href="{{ route('users.index') }}" class="btn btn-warning btn-sm">Batal</a>
<button type="submit" class="btn btn-primary btn-sm">Simpan</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
@endsectionPenjelasan kode: - findOrFail($id) — mengambil data user berdasarkan ID; jika tidak ditemukan, otomatis melempar error 404 (lebih aman daripada find() yang mengembalikan null) - <input type="hidden" name="_method" value="PUT"> — method spoofing untuk mengirim request PUT melalui form HTML - value="{{ $user->name }}" — mengisi nilai default form dengan data yang sudah ada di database - in_array("ADMIN", json_decode($user->level)) ? "selected" : "" — logika untuk menandai option yang sesuai dengan level user saat ini; json_decode mengubah JSON string kembali menjadi array PHP
7.5 — DELETE — Hapus User
Tombol hapus sudah disertakan di user/index.blade.php (lihat langkah READ). Berikut method destroy di controller: File: app/Http/Controllers/UserController.php — method destroy:
public function destroy($id)
{
$user = \App\Models\User::findOrFail($id);
$user->delete();
return redirect()->route('users.index')->with('status', 'User berhasil dihapus');
}Penjelasan kode: - findOrFail($id) — memastikan data ada sebelum mencoba menghapus - $user->delete() — menghapus record dari database menggunakan Eloquent; query DELETE FROM users WHERE id = ? dieksekusi secara otomatis di balik layar - Setelah penghapusan, dilakukan redirect dengan flash message sukses