PRAKTIKUM 10 PEMROGRAMAN WEB

Mempelajari tentang:
• 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)

Migration Database

Migration adalah cara Laravel untuk membuat dan mengelola struktur tabel di database melalui kode PHP. Dengan migration, kita bisa membangun, mengubah, dan menghapus tabel secara versi terkontrol.

A. Migration untuk Tabel majors

Pada file migration ini, kita membuat struktur tabel majors, yang berisi:

timestamps(): untuk menyimpan waktu pembuatan dan pembaruan (created_at, updated_at)

id: kunci utama (auto increment)

name: nama jurusan, bertipe string

php artisan make:migration create_majors_table

Dalam fungsi up(), kita mendefinisikan struktur tabel:

Schema::create('majors', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});

Tabel ini adalah referensi utama untuk relasi ke mahasiswa.

B. Migration untuk Tabel students

Tabel ini menyimpan data mahasiswa. Perintah:

php artisan make:migration create_students_table

Strukturnya:

  • nim dan name menyimpan identitas mahasiswa
  • address menyimpan alamat
  • major_id adalah foreign key yang merujuk ke tabel majors
  • onDelete('cascade') berarti jika jurusan dihapus, data mahasiswa juga ikut dihapus

Struktur tabel mahasiswa:

  • nim: nomor induk mahasiswa (unik)
  • name: nama mahasiswa
  • address: alamat mahasiswa
  • major_id: foreign key yang menunjuk ke tabel majors
  • timestamps(): waktu catatan dibuat/diperbarui
$table->foreignId('major_id')
->constrained('majors')
->onDelete('cascade');

Artinya, jika suatu jurusan dihapus, seluruh mahasiswa dalam jurusan itu juga otomatis terhapus.


C. Migration: subjects Table

php artisan make:migration create_subjects_table

Tabel ini menyimpan informasi mata kuliah:

  • name: nama mata kuliah
  • sks: jumlah satuan kredit semester
  • timestamps()

Sangat penting karena akan direlasikan ke mahasiswa melalui pivot table.


D. Migration: student_subject (Pivot Table)

php artisan make:migration create_student_subject_table

Pivot table ini bertujuan untuk menghubungkan mahasiswa dan mata kuliah secara many-to-many:

  • Satu mahasiswa bisa mengambil banyak mata kuliah.
  • Satu mata kuliah bisa diambil oleh banyak mahasiswa.
$table->foreignId('student_id')->constrained('students')->onDelete('cascade');
$table->foreignId('subject_id')->constrained('subjects')->onDelete('cascade');
$table->unique(['student_id', 'subject_id']);

unique() digunakan untuk mencegah mahasiswa mengambil mata kuliah yang sama lebih dari satu kali.


Jalankan Migration:

php artisan migrate

Jika berhasil, keempat tabel akan muncul di database.


2. MODEL – Representasi Objek & Relasi Antar Tabel

Model adalah penghubung antara tabel di database dan logika bisnis aplikasi. Laravel menyediakan Eloquent ORM untuk mempermudah pemetaan ini.


A. Model Major

php artisan make:model Major
public function students() {
return $this->hasMany(Student::class);
}
  • Ini adalah relasi one-to-many, satu jurusan memiliki banyak mahasiswa.
  • fillable berisi atribut yang bisa di-mass-assign, seperti saat membuat objek dengan create().

B. Model Student

php artisan make:model Student
public function major() {
return $this->belongsTo(Major::class);
}
public function subjects() {
return $this->belongsToMany(Subject::class);
}
  • belongsTo(Major::class) → mahasiswa memiliki satu jurusan.
  • belongsToMany(Subject::class) → mahasiswa bisa mengambil banyak mata kuliah melalui pivot table.
  • Pastikan tidak ada typo: gunakan ->belongsToMany(), bukan ->>belongsToMany().

C. Model Subject

php artisan make:model Subject
public function students() {
return $this->belongsToMany(Student::class);
}
  • Ini adalah kebalikan dari relasi mahasiswa.
  • Setiap mata kuliah bisa diambil banyak mahasiswa.

3. SEEDER – Mengisi Database dengan Data Awal

Seeder membantu mengisi database dengan data awal (dummy) agar bisa langsung digunakan atau diuji.


A. Seeder MajorSeeder

php artisan make:seeder MajorSeeder
$majors = [
['name' => 'Teknik Informatika'],
['name' => 'Sistem Informasi'],
['name' => 'Teknik Komputer'],
['name' => 'Manajemen Informatika'],
];

foreach ($majors as $major) {
Major::create($major);
}

Seeder ini membuat 4 jurusan dan menyimpannya ke tabel majors.


B. Seeder SubjectSeeder

php artisan make:seeder SubjectSeeder
$subjects = [
['name' => 'Pemrograman Web', 'sks' => 3],
['name' => 'Database', 'sks' => 3],
['name' => 'Algoritma', 'sks' => 2],
['name' => 'Jaringan Komputer', 'sks' => 3],
['name' => 'Sistem Operasi', 'sks' => 2],
];

Seeder ini mengisi daftar mata kuliah lengkap dengan nilai SKS-nya.


C. Seeder StudentSeeder

php artisan make:seeder StudentSeeder

Seeder ini:

  1. Membuat 5 mahasiswa dengan data lengkap.
  2. Untuk setiap mahasiswa, dipilih 2–4 mata kuliah secara acak.
  3. Lalu disambungkan ke pivot table student_subject.
$student->subjects()->attach($subjects);

Ini membuat setiap mahasiswa memiliki relasi ke beberapa mata kuliah sekaligus.


D. Update DatabaseSeeder

public function run()
{
$this->call([
MajorSeeder::class,
SubjectSeeder::class,
StudentSeeder::class,
]);
}

Seeder utama ini memanggil semua seeder lainnya agar bisa dijalankan sekaligus.


Jalankan Seeder:

php artisan db:seed

Setelah dijalankan, maka:

  • Semua jurusan terisi
  • Semua mata kuliah tersedia
  • Mahasiswa lengkap dengan jurusannya
  • Pivot table terisi otomatis

4. Membuat Controller

A. StudentController

php artisan make:controller StudentController

Ketik 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() {
        $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() {
        return view('students.create', [
            'majors' => Major::all(),
            'subjects' => Subject::all()
        ]);
    }

    public function store(Request $r) {
        $r->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($r->only(['nim', 'name', 'address', 'major_id']));
        $student->subjects()->attach($r->subjects);
        return redirect()->route('students.index')->with('success', 'Student created');
    }

    public function edit($id) {
        return view('students.edit', [
            'student' => Student::with('subjects')->findOrFail($id),
            'majors' => Major::all(),
            'subjects' => Subject::all()
        ]);
    }

    public function update(Request $r, $id) {
        $student = Student::findOrFail($id);
        $r->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($r->only(['nim', 'name', 'address', 'major_id']));
        $student->subjects()->sync($r->subjects);
        return redirect()->route('students.index')->with('success', 'Student updated');
    }

    public function destroy($id) {
        $student = Student::findOrFail($id);
        $student->subjects()->detach();
        $student->delete();
        return redirect()->route('students.index')->with('success', 'Student deleted');
    }
}

5. Membuat Routes

  • Mengarahkan '/' ke daftar mahasiswa.
  • Route::resource() otomatis membuat semua route CRUD untuk mahasiswa.

Ketik kode berikut di web.php :

 >?php 
 // routes/web.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\StudentController;

Route::get('/', fn() => redirect()->route('students.index'));
Route::resource('students', StudentController::class);

6. Membuat Views

A. Layout utama

  • Template HTML utama. Menyediakan navbar, tampilan notifikasi success, dan slot @yield('content') untuk konten halaman.
{{-- resources/views/layouts/app.blade.php --}}

Buat file pada resources/views/layouts/app.blade.php. kodenya adalah seperti berikut:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Student Management</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-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>
</body>
</html>

B. Index Students

Menampilkan tabel mahasiswa dengan NIM, nama, jurusan, mata kuliah, total SKS, dan tombol aksi (detail, edit, hapus).

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 mb-4">
    <h2>Daftar Mahasiswa</h2>
    <a href="{{ route('students.create') }}" class="btn btn-primary">Tambah</a>
</div>
<table class="table table-bordered">
    <thead>
        <tr><th>NIM</th><th>Nama</th><th>Jurusan</th><th>Mata Kuliah</th><th>SKS</th><th>Aksi</th></tr>
    </thead>
    <tbody>
        @foreach($students as $s)
        <tr>
            <td>{{ $s->nim }}</td>
            <td>{{ $s->name }}</td>
            <td>{{ $s->major->name }}</td>
            <td>
                @foreach($s->subjects as $sub)
                    <span class="badge bg-secondary">{{ $sub->name }}</span>
                @endforeach
            </td>
            <td>{{ $s->subjects->sum('sks') }}</td>
            <td>
                <a href="{{ route('students.show', $s->id) }}" class="btn btn-info btn-sm">Detail</a>
                <a href="{{ route('students.edit', $s->id) }}" class="btn btn-warning btn-sm">Edit</a>
                <form method="POST" action="{{ route('students.destroy', $s->id) }}" class="d-inline">
                    @csrf @method('DELETE')
                    <button class="btn btn-danger btn-sm" onclick="return confirm('Yakin?')">Hapus</button>
                </form>
            </td>
        </tr>
        @endforeach
    </tbody>
</table>
@endsection

C. Create Student

{{-- resources/views/students/create.blade.php --}}

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
            @foreach (['nim'=>'NIM', 'name'=>'Nama', 'address'=>'Alamat'] as $f => $label)
            <div class="mb-3">
                <label class="form-label">{{ $label }}</label>
                <input type="text" name="{{ $f }}" class="form-control @error($f) is-invalid @enderror"
                       value="{{ old($f) }}">
                @error($f) <div class="invalid-feedback">{{ $message }}</div> @enderror
            </div>
            @endforeach

            <div class="mb-3">
                <label>Jurusan</label>
                <select name="major_id" class="form-control @error('major_id') is-invalid @enderror">
                    <option value="">Pilih Jurusan</option>
                    @foreach($majors as $m)
                        <option value="{{ $m->id }}" {{ old('major_id') == $m->id ? 'selected' : '' }}>
                            {{ $m->name }}
                        </option>
                    @endforeach
                </select>
                @error('major_id') <div class="invalid-feedback">{{ $message }}</div> @enderror
            </div>

            <div class="mb-3">
                <label>Mata Kuliah</label>
                @error('subjects') <div class="text-danger">{{ $message }}</div> @enderror
                @foreach($subjects as $sub)
                <div class="form-check">
                    <input class="form-check-input" type="checkbox" name="subjects[]"
                           value="{{ $sub->id }}" id="sub{{ $sub->id }}"
                           {{ in_array($sub->id, old('subjects', [])) ? 'checked' : '' }}>
                    <label class="form-check-label" for="sub{{ $sub->id }}">
                        {{ $sub->name }} ({{ $sub->sks }} SKS)
                    </label>
                </div>
                @endforeach
            </div>

            <button class="btn btn-primary">Simpan</button>
            <a href="{{ route('students.index') }}" class="btn btn-secondary">Kembali</a>
        </form>
    </div>
</div>
@endsection

Leave a Comment

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