Pada pertemuan kali ini, kita akan membuat sistem akademik sederhana dengan relationship:
- Student belongs to Major (Many-to-One)
- Student belongs to many Subject through pivot table (Many-to-Many)
- Major has many Student (One-to-Many)
- Subject belongs to many Student through pivot table (Many-to-Many)
Untuk detailnya, berikut adalah ERD untuk database yang akan kita implementasikan pada project:


Untuk pertemuan kali ini, kita perlu membuat project baru karena database yang digunakan adalah database baru. Spesifikasi database yang digunakan yaitu cukup menggunakan SQLite.
Setelah membuat project baru secara lokal, langkah pertama yang dilakukan adalah membuat migrasi database.
A. Migration untuk tabel majors
Buat migrasi database dengan menggunakan command berikut di terminal:
php artisan make:migration create_majors_tableKemudian tambahkan kode berikut di function up():
Schema::create('majors', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});B. Migration untuk tabel students
Buat migrasi database dengan menggunakan command berikut di terminal:
php artisan make:migration create_students_tableKemudian tambahkan kode berikut di function up():
Schema::create('students', function (Blueprint $table) {
$table->id();
$table->string('nim')->unique();
$table->string('name');
$table->text('address');
$table->foreignId('major_id')->constrained('majors')->onDelete('cascade');
$table->timestamps();
});C. Migration untuk tabel subjects
Buat migrasi database dengan menggunakan command berikut di terminal:
php artisan make:migration create_subjects_tableKemudian tambahkan kode berikut di function up():
Schema::create('subjects', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->integer('sks');
$table->timestamps();
});D. Migration untuk tabel pivot student_subject
Buat migrasi database dengan menggunakan command berikut di terminal:
php artisan make:migration create_student_subject_tableKemudian tambahkan kode berikut di function up():
Schema::create('student_subject', function (Blueprint $table) {
$table->id();
$table->foreignId('student_id')->constrained('students')->onDelete('cascade');
$table->foreignId('subject_id')->constrained('subjects')->onDelete('cascade');
$table->timestamps();
// Mencegah duplikasi kombinasi student_id dan subject_id
$table->unique(['student_id', 'subject_id']);
});Setelah semua migrasi telah dibuat dan disave, jalankan migrasi database dengan perintah terminal:
php artisan migrateJika berhasil, maka akan seperti berikut:

Langkah selanjutnya yaitu membuat model dengan relationship sesuai dengan migrasi database yang telah dibuat.
A, Model Major
Buat model dengan menggunakan command berikut di terminal:
php artisan make:model MajorSetelah itu, masukkan kode berikut di model:
<?php
// app/Models/Major.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Major extends Model
{
use HasFactory;
protected $fillable = ['name'];
// Relationship: One Major has many Students
public function students()
{
return $this->hasMany(Student::class);
}
}B. Model Student
Buat model dengan menggunakan command berikut di terminal:
php artisan make:model StudentSetelah itu, masukkan kode berikut di model:
<?php
// app/Models/Student.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Student extends Model
{
use HasFactory;
protected $fillable = ['nim', 'name', 'address', 'major_id'];
// Relationship: Many Students belong to one Major
public function major()
{
return $this->belongsTo(Major::class);
}
// Relationship: Many Students belong to many Subjects
public function subjects()
{
return $this->belongsToMany(Subject::class);
}
} C. Model Subject
Buat model dengan menggunakan command berikut di terminal:
php artisan make:model Subject Setelah itu, masukkan kode berikut di model:
<?php
// app/Models/Subject.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Subject extends Model
{
use HasFactory;
protected $fillable = ['name', 'sks'];
// Relationship: Many Subjects belong to many Students
public function students()
{
return $this->belongsToMany(Student::class);
}
}
Langkah selanjutnya yaitu membuat sebuah seeder untuk memasukkan data ke dalam database.
A. Seeder untuk Major
Buat seeder dengan menggunakan command berikut di terminal:
php artisan make:seeder MajorSeederSetelah itu, masukkan kode berikut di seeder:
<?php
// database/seeders/MajorSeeder.php
namespace Database\Seeders;
use App\Models\Major;
use Illuminate\Database\Seeder;
class MajorSeeder extends Seeder
{
public function run()
{
$majors = [
['name' => 'Teknik Informatika'],
['name' => 'Sistem Informasi'],
['name' => 'Teknik Komputer'],
['name' => 'Manajemen Informatika'],
];
foreach ($majors as $major) {
Major::create($major);
}
}
} B. Seeder untuk Subject
Buat seeder dengan menggunakan command berikut di terminal:
php artisan make:seeder SubjectSeederSetelah itu, masukkan kode berikut di seeder:
<?php
// database/seeders/SubjectSeeder.php
namespace Database\Seeders;
use App\Models\Subject;
use Illuminate\Database\Seeder;
class SubjectSeeder extends Seeder
{
public function run()
{
$subjects = [
['name' => 'Pemrograman Web', 'sks' => 3],
['name' => 'Database', 'sks' => 3],
['name' => 'Algoritma', 'sks' => 2],
['name' => 'Jaringan Komputer', 'sks' => 3],
['name' => 'Sistem Operasi', 'sks' => 2],
];
foreach ($subjects as $subject) {
Subject::create($subject);
}
}
} C. Seeder untuk Student
Buat seeder dengan menggunakan command berikut di terminal:
php artisan make:seeder StudentSeederSetelah itu, masukkan kode berikut di seeder:
<?php
// database/seeders/StudentSeeder.php
namespace Database\Seeders;
use App\Models\Student;
use App\Models\Major;
use App\Models\Subject;
use Illuminate\Database\Seeder;
class StudentSeeder extends Seeder
{
public function run()
{
$students = [
['nim' => '20210001', 'name' => 'Ahmad Rizki', 'address' => 'Jl. Merdeka No. 1',
'major_id' => 1],
['nim' => '20210002', 'name' => 'Siti Nurhaliza', 'address' => 'Jl. Sudirman No.
15', 'major_id' => 1],
['nim' => '20210003', 'name' => 'Budi Santoso', 'address' => 'Jl. Pahlawan No. 8',
'major_id' => 2],
['nim' => '20210004', 'name' => 'Dewi Kartika', 'address' => 'Jl. Diponegoro No.
22', 'major_id' => 2],
['nim' => '20210005', 'name' => 'Eko Prasetyo', 'address' => 'Jl. Gatot Subroto No.
11', 'major_id' => 3],
];
foreach ($students as $studentData) {
$student = Student::create($studentData);
// Assign random subjects to each student
$subjects = Subject::inRandomOrder()->take(rand(2, 4))->pluck('id');
$student->subjects()->attach($subjects);
}
}
} D. Update DatabaseSeeder
Tambahkan kode berikut di DatabaseSeeder
<?php
// database/seeders/DatabaseSeeder.php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run()
{
$this->call([
MajorSeeder::class,
SubjectSeeder::class,
StudentSeeder::class,
]);
}
} Setelah semua seeder dibuat dan di save, jalankan seeder dengan perintah terminal:
php artisan db:seedJika berhasil maka akan seperti berikut:

Langkah selanjutnya yaitu membuat controller pada masing-masing model.
A. StudentController
Buat controller dengan perintah terminal berikut:
php artisan make:controller StudentControllerKemudian, tambahkan kode berikut di file controller:
<?php
// app/Http/Controllers/StudentController.php
namespace App\Http\Controllers;
use App\Models\Student;
use App\Models\Major;
use App\Models\Subject;
use Illuminate\Http\Request;
class StudentController extends Controller
{
public function index()
{
// Eager loading untuk menghindari N+1 problem
$students = Student::with(['major', 'subjects'])->get();
return view('students.index', compact('students'));
}
public function show($id)
{
$student = Student::with(['major', 'subjects'])->findOrFail($id);
return view('students.show', compact('student'));
}
public function create()
{
$majors = Major::all();
$subjects = Subject::all();
return view('students.create', compact('majors', 'subjects'));
}
public function store(Request $request)
{
$request->validate([
'nim' => 'required|unique:students',
'name' => 'required',
'address' => 'required',
'major_id' => 'required|exists:majors,id',
'subjects' => 'required|array',
'subjects.*' => 'exists:subjects,id',
]);
$student = Student::create($request->only(['nim', 'name', 'address', 'major_id']));
$student->subjects()->attach($request->subjects);
return redirect()->route('students.index')->with('success', 'Student created
successfully');
}
public function edit($id)
{
$student = Student::with('subjects')->findOrFail($id);
$majors = Major::all();
$subjects = Subject::all();
return view('students.edit', compact('student', 'majors', 'subjects'));
}
public function update(Request $request, $id)
{
$student = Student::findOrFail($id);
$request->validate([
'nim' => 'required|unique:students,nim,' . $student->id,
'name' => 'required',
'address' => 'required',
'major_id' => 'required|exists:majors,id',
'subjects' => 'required|array',
'subjects.*' => 'exists:subjects,id',
]);
$student->update($request->only(['nim', 'name', 'address', 'major_id']));
$student->subjects()->sync($request->subjects);
return redirect()->route('students.index')->with('success', 'Student updated
successfully');
}
public function destroy($id)
{
$student = Student::findOrFail($id);
$student->subjects()->detach(); // Remove all subject relationships
$student->delete();
return redirect()->route('students.index')->with('success', 'Student deleted
successfully');
}
} Langkah selanjutnya yaitu membuat Route untuk menentukan bagaimana aplikasi merespons permintaan (request) pada URL tertentu. Tambahkan kode ini di web.php
<?php
// routes/web.php
use App\Http\Controllers\StudentController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return redirect()->route('students.index');
});
Route::resource('students', StudentController::class);Langkah selanjutnya yaitu membuat views untuk menampilkan pada halaman website.
A. Layout utama
Buat file pada resources/views/layouts/app.blade.php. kodenya adalah seperti berikut:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Student Management System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a class="navbar-brand" href="{{ route('students.index') }}">Student Management</a>
</div>
</nav>
<div class="container mt-4">
@if(session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
@yield('content')
</div>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>B. Index Students
Buat file pada resources/views/students/index.blade.php. kodenya adalah seperti berikut:
@extends('layouts.app')
@section('content')
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Daftar Mahasiswa</h2>
<a href="{{ route('students.create') }}" class="btn btn-primary">Tambah Mahasiswa</a>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>NIM</th>
<th>Nama</th>
<th>Jurusan</th>
<th>Mata Kuliah</th>
<th>Total SKS</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@foreach($students as $student)
<tr>
<td>{{ $student->nim }}</td>
<td>{{ $student->name }}</td>
<td>{{ $student->major->name }}</td>
<td>
@foreach($student->subjects as $subject)
<span class="badge bg-secondary me-1">{{ $subject->name }}</span>
@endforeach
</td>
<td>{{ $student->subjects->sum('sks') }}</td>
<td>
<a href="{{ route('students.show', $student->id) }}" class="btn btn-info
btn-sm">Detail</a>
<a href="{{ route('students.edit', $student->id) }}" class="btn btn-warning
btn-sm">Edit</a>
<form action="{{ route('students.destroy', $student->id) }}" method="POST"
class="d-inline">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger btn-sm"
onclick="return confirm('Yakin ingin
menghapus?')">Hapus</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endsectionC. Create Student
Buat file pada resources/views/students/create.blade.php. kodenya adalah seperti berikut:
@extends('layouts.app')
@section('content')
<h2>Tambah Mahasiswa</h2>
<div class="card">
<div class="card-body">
<form action="{{ route('students.store') }}" method="POST">
@csrf
<div class="mb-3">
<label for="nim" class="form-label">NIM</label>
<input type="text" class="form-control @error('nim') is-invalid @enderror"
id="nim" name="nim" value="{{ old('nim') }}">
@error('nim')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="name" class="form-label">Nama</label>
<input type="text" class="form-control @error('name') is-invalid @enderror"
id="name" name="name" value="{{ old('name') }}">
@error('name')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="address" class="form-label">Alamat</label>
<input type="text" class="form-control @error('address') is-invalid @enderror"
id="address" name="address" value="{{ old('address') }}">
@error('address')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="major_id" class="form-label">Jurusan</label>
<select name="major_id" id="major_id" class="form-control @error('major_id') is-invalid @enderror" >
<option value="">Pilih Jurusan</option>
@foreach ($majors as $major)
<option value="{{ $major->id }}" {{ old('major_id') == $major->id ? 'selected' : '' }}>
{{ $major->name }}
</option>
@endforeach
</select>
@error('major_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label class="form-label">Mata Kuliah</label>
@error('subjects')
<div class="text-danger">{{ $message }}</div>
@enderror
@foreach ($subjects as $subject)
<div class="form-check">
<input type="checkbox" class="form-check-input" name="subjects[]"
value="{{ $subject->id }}" id="subject{{ $subject->id }}"
{{ in_array($subject->id, old('subjects', [])) ? 'checked' : '' }}>
<label for="subject{{ $subject->id }}" class="form-check-label">
{{ $subject->name }} ({{ $subject->sks }} SKS)
</label>
</div>
@endforeach
</div>
<button type="submit" class="btn btn-primary">Simpan</button>
<a href="{{ route('students.index') }}" class="btn btn-secondary">Kembali</a>
</form>
</div>
</div>
@endsectionJika sudah, maka tampilannya akan seperti berikut:
A. Index

B. Create

Tugas
- Query untuk menampilkan Jurusan yang memiliki mahasiswa terbanyak
Pertama, kita ubah terlebih dahulu di StudentController. Tambah kode berikut di Index()
$mostFrequentMajor = Major::withCount('students') // Count students for each major
->orderByDesc('students_count') // Order by the count descending
->first();Query ini berfungsi untuk mencari dan mengambil satu data jurusan (Major) yang memiliki jumlah mahasiswa terbanyak. Langkah pertamanya (Major::withCount(‘students’)) adalah mengambil semua data jurusan sambil menghitung jumlah mahasiswa yang berelasi dengan setiap jurusan, hasil hitungan ini disimpan dalam kolom virtual bernama students_count; kemudian (orderByDesc(‘students_count’)) hasilnya diurutkan secara menurun berdasarkan jumlah mahasiswa tersebut; dan terakhir (first()) diambil satu record pertama dari hasil pengurutan, yang secara efektif adalah jurusan dengan jumlah mahasiswa terbanyak.
Kemudian pada index dibawah tabel tambahkan kode berikut:
@if ($mostFrequentMajor)
<div class="alert alert-info mt-4" role="alert">
Jurusan yang paling banyak dipilih mahasiswa adalah: <strong>{{ $mostFrequentMajor->name }}</strong> (dengan {{ $mostFrequentMajor->students_count }} mahasiswa).
</div>
@endifHasilnya akan menjadi seperti berikut:

2. Menambahkan View Detail menggunakan controller show()
Kode viewnya adalah seperti berikut:
@extends('layouts.app')
@section('content')
<h2>Detail Mahasiswa</h2>
<div class="card">
<div class="card-body">
<div class="mb-3">
<label for="nim" class="form-label">NIM:</label>
<p id="nim">{{ $student->nim }}</p>
</div>
<div class="mb-3">
<label for="name" class="form-label">Nama:</label>
<p id="name">{{ $student->name }}</p>
</div>
<div class="mb-3">
<label for="address" class="form-label">Alamat:</label>
<p id="address">{{ $student->address }}</p>
</div>
<div class="mb-3">
<label for="major" class="form-label">Jurusan:</label>
<p id="major">{{ $student->major->name }}</p>
</div>
<div class="mb-3">
<label class="form-label">Mata Kuliah Diambil:</label>
@if ($student->subjects->count() > 0)
<ul>
@foreach ($student->subjects as $subject)
<li>{{ $subject->name }} ({{ $subject->sks }} SKS)</li>
@endforeach
</ul>
<p><strong>Total SKS:</strong> {{ $student->subjects->sum('sks') }}</p>
@else
<p>Tidak ada mata kuliah yang diambil.</p>
@endif
</div>
<a href="{{ route('students.index') }}" class="btn btn-secondary">Kembali ke Daftar</a>
</div>
</div>
@endsectionHasilnya adalah sebagai berikut:

3. Menambahkan view edit dari controller update()
Kode viewnya adalah sebagai berikut:
@extends('layouts.app')
@section('content')
<h2>Edit Mahasiswa</h2>
<div class="card">
<div class="card-body">
<form action="{{ route('students.update', $student->id) }}" method="POST">
@csrf
@method('PUT') {{-- Use PUT method for updates --}}
<div class="mb-3">
<label for="nim" class="form-label">NIM</label>
{{-- Populate with existing student data, or old input on validation error --}}
<input type="text" class="form-control @error('nim') is-invalid @enderror"
id="nim" name="nim" value="{{ old('nim', $student->nim) }}">
@error('nim')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="name" class="form-label">Nama</label>
<input type="text" class="form-control @error('name') is-invalid @enderror"
id="name" name="name" value="{{ old('name', $student->name) }}">
@error('name')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="address" class="form-label">Alamat</label>
<input type="text" class="form-control @error('address') is-invalid @enderror"
id="address" name="address" value="{{ old('address', $student->address) }}">
@error('address')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label for="major_id" class="form-label">Jurusan</label>
<select name="major_id" id="major_id" class="form-control @error('major_id') is-invalid @enderror" >
<option value="">Pilih Jurusan</option>
@foreach ($majors as $major)
{{-- Pre-select the current major --}}
<option value="{{ $major->id }}" {{ old('major_id', $student->major_id) == $major->id ? 'selected' : '' }}>
{{ $major->name }}
</option>
@endforeach
</select>
@error('major_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<div class="mb-3">
<label class="form-label">Mata Kuliah</label>
@error('subjects')
<div class="text-danger">{{ $message }}</div>
@enderror
@foreach ($subjects as $subject)
<div class="form-check">
<input type="checkbox" class="form-check-input" name="subjects[]"
value="{{ $subject->id }}" id="subject{{ $subject->id }}"
{{-- Check if the subject is currently associated with the student --}}
{{ in_array($subject->id, old('subjects', $student->subjects->pluck('id')->toArray())) ? 'checked' : '' }}>
<label for="subject{{ $subject->id }}" class="form-check-label">
{{ $subject->name }} ({{ $subject->sks }} SKS)
</label>
</div>
@endforeach
</div>
<button type="submit" class="btn btn-primary">Update</button>
<a href="{{ route('students.index') }}" class="btn btn-secondary">Batal</a>
</form>
</div>
</div>
@endsectionTampilannya adalah seperti berikut:
