Laporan Praktikum Pemrograman Web Pertemuan 10

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_table

Kemudian 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_table

Kemudian 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_table

Kemudian 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_table

Kemudian 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 migrate

Jika 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 Major

Setelah 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 Student

Setelah 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 MajorSeeder

Setelah 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 SubjectSeeder

Setelah 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 StudentSeeder

Setelah 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:seed

Jika 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 StudentController

Kemudian, 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> 
@endsection

C. 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>
@endsection

Jika sudah, maka tampilannya akan seperti berikut:

A. Index

B. Create

Tugas

  1. 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>
@endif

Hasilnya 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>
@endsection

Hasilnya 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>
@endsection

Tampilannya adalah seperti berikut:

Leave a Comment

Your email address will not be published. Required fields are marked *