Laporan Praktikum 8

Laravel Relationship: Student, Major, dan Subject

Dibuat : 25 Mei 2026

Repository GitHub

Pendahuluan

Dalam membangun aplikasi web yang scalable dengan Laravel, salah satu aspek terpenting adalah kemampuan untuk mengelola hubungan antar data (relationship) dengan baik. Database relasional modern memerlukan pendekatan yang terstruktur untuk menghubungkan berbagai entitas sehingga integritas dan konsistensi data tetap terjaga.

Laravel menyediakan fitur Eloquent ORM (Object-Relational Mapping) yang powerful untuk memetakan hubungan tabel database ke dalam bentuk objek yang mudah digunakan. Melalui pendekatan ini, developer tidak perlu menulis query SQL yang rumit, cukup dengan mendefinisikan method relasi di dalam Model.

Praktikum ini bertujuan memahami dan mengimplementasikan dua jenis relasi fundamental yaitu One-to-Many dan Many-to-Many melalui studi kasus sistem akademik yang menghubungkan data program studi (Major), mahasiswa (Student), dan mata kuliah (Subject).

Tujuan Praktikum

  • Memahami konsep relationship dalam database relasional dan implementasinya di Laravel Eloquent.
  • Mampu membuat file migration dengan proper foreign key constraint dan cascade delete.
  • Mengimplementasikan relasi One-to-Many antara Major dan Student, serta Many-to-Many antara Student dan Subject.
  • Menerapkan teknik Eager Loading untuk mengoptimalkan performa query database.
  • Menggunakan method seperti attach(), sync() untuk mengelola relasi Many-to-Many.
  • Menampilkan data berelasi dengan kompleks di halaman view dengan struktur yang rapi.

Landasan Teori

Relationship atau relasi adalah hubungan antar tabel dalam database yang digunakan untuk menghubungkan data secara logis dan menjaga integritas referensial.

Relasi One-to-Many menggambarkan hubungan di mana satu record dari tabel parent dapat memiliki banyak record di tabel child. Contoh: satu program studi (Major) dapat memiliki banyak mahasiswa (Student). Pada tabel child, disimpan foreign key yang mereferensi primary key tabel parent.

Relasi Many-to-Many menggambarkan hubungan di mana banyak record dari tabel A dapat memiliki hubungan dengan banyak record dari tabel B. Untuk mewujudkan ini, diperlukan tabel perantara (pivot table) yang menyimpan foreign key dari kedua tabel tersebut. Contoh: banyak mahasiswa dapat mengambil banyak mata kuliah.

Eloquent ORM adalah sistem yang mengubah tabel database menjadi objek yang dapat dimanipulasi melalui kode PHP. Dengan method-method seperti hasMany(), belongsTo(), dan belongsToMany(), developer dapat mendefinisikan relasi antar model tanpa query SQL manual.

N+1 problem terjadi ketika melakukan query di dalam loop, menyebabkan banyak database calls yang tidak efisien. Eager Loading menggunakan method with() untuk memuat relasi bersamaan dengan data utama dalam satu query, mengurangi beban database secara signifikan.

Pivot table adalah tabel perantara yang menyimpan dua foreign key. Method attach() digunakan untuk menambahkan relasi baru, sedangkan sync() digunakan untuk sinkronisasi relasi dengan menghapus yang tidak ada dalam array baru dan menambahkan yang baru.

Alat dan Bahan

  • Laptop / Komputer
  • XAMPP (Apache + MySQL)
  • Visual Studio Code
  • Composer, Git, Node.js, NPM
  • Database Management: phpMyAdmin
  • Browser (Google Chrome / Firefox)

Langkah Pengerjaan

1. Persiapan Project dan Database

Melanjutkan project laravel dari praktikum 7. Buka file .env dan pastikan konfigurasi detail koneksi database sesuai:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=example_app
DB_USERNAME=root
DB_PASSWORD=

2. Membuat Migration File untuk Tabel Majors

Langkah pertama adalah membangun struktur tabel untuk program studi (Majors). Buat migration file baru:

php artisan make:migration create_majors_table

Buka file migration yang baru dibuat di database/migrations dan isi dengan skema tabel majors:

<?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::create('majors', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('majors');
    }
};

Tabel majors memiliki kolom id sebagai primary key, name untuk menyimpan nama program studi, serta timestamps untuk mencatat waktu pembuatan dan perubahan data.


3. Membuat Migration File untuk Tabel Students

Selanjutnya buat migration file untuk tabel mahasiswa dengan relasi One-to-Many ke tabel majors:

php artisan make:migration create_students_table

Isi file migration students dengan kode berikut yang menyertakan foreign key ke tabel majors:

<?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::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();
        });
    }

    public function down()
    {
        Schema::dropIfExists('students');
    }
};

Pada tabel students, kolom major_id berfungsi sebagai foreign key yang mereferensi tabel majors. Pengaturan onDelete('cascade') memastikan ketika satu program studi dihapus, semua mahasiswa di program studi tersebut akan terhapus otomatis.


4. Membuat Migration File untuk Tabel Subjects

Buat migration file untuk tabel mata kuliah:

php artisan make:migration create_subjects_table

Isi file migration subjects dengan skema yang menyimpan data mata kuliah:

<?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::create('subjects', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->integer('sks');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('subjects');
    }
};

Tabel subjects menyimpan nama mata kuliah dan jumlah kredit (SKS). Tabel ini akan terhubung dengan tabel students melalui relasi Many-to-Many.


5. Membuat Migration File untuk Tabel Pivot Student_Subject

Untuk mendukung relasi Many-to-Many, buat tabel perantara (pivot table) yang menghubungkan students dan subjects:

php artisan make:migration create_student_subject_table

Isi file migration dengan struktur pivot table:

<?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::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 kombinasi student_id dan subject_id yang sama tersimpan lebih dari sekali
            $table->unique(['student_id', 'subject_id']);
        });
    }

    public function down()
    {
        Schema::dropIfExists('student_subject');
    }
};

Tabel pivot ini menyimpan dua foreign key yang mereferensi students dan subjects. Constraint unique mencegah seorang mahasiswa terdaftar pada mata kuliah yang sama berkali-kali.

Setelah semua migration file dibuat, jalankan perintah migrate untuk membuat tabel di database:

php artisan migrate

6. Membuat Model dengan Definisi Relationship

Buat Model Major dengan method relasi ke Student:

php artisan make:model Major

Buka file app/Models/Major.php dan definisikan relasi One-to-Many:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Major extends Model
{
    protected $fillable = ['name'];

    public function students(): HasMany
    {
        return $this->hasMany(Student::class);
    }
}

Buat Model Student dengan method relasi ke Major dan Subject:

php artisan make:model Student

Isi app/Models/Student.php dengan definisi kedua relasi:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Student extends Model
{
    protected $fillable = ['nim', 'name', 'address', 'major_id'];

    public function major(): BelongsTo
    {
        return $this->belongsTo(Major::class);
    }

    public function subjects(): BelongsToMany
    {
        return $this->belongsToMany(Subject::class);
    }
}

Buat Model Subject dengan method relasi ke Student:

php artisan make:model Subject

Isi app/Models/Subject.php:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Subject extends Model
{
    protected $fillable = ['name', 'sks'];

    public function students(): BelongsToMany
    {
        return $this->belongsToMany(Student::class);
    }
}

7. Membuat Seeder untuk Data Dummy

Buat seeder untuk program studi:

php artisan make:seeder MajorSeeder

Isi database/seeders/MajorSeeder.php:

<?php

namespace Database\Seeders;

use App\Models\Major;
use Illuminate\Database\Seeder;

class MajorSeeder extends Seeder
{
    public function run()
    {
        $majors = [
            'Teknik Informatika',
            'Sistem Informasi',
            'Teknik Komputer',
            'Keamanan Siber'
        ];

        foreach ($majors as $major) {
            Major::create(['name' => $major]);
        }

        $this->command->info('Major seeder berhasil dijalankan');
    }
}

Buat seeder untuk mata kuliah:

php artisan make:seeder SubjectSeeder

Isi database/seeders/SubjectSeeder.php:

<?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' => 'Basis Data', 'sks' => 3],
            ['name' => 'Algoritma dan Struktur Data', 'sks' => 4],
            ['name' => 'Jaringan Komputer', 'sks' => 3],
            ['name' => 'Sistem Operasi', 'sks' => 3],
            ['name' => 'Keamanan Informasi', 'sks' => 3]
        ];

        foreach ($subjects as $subject) {
            Subject::create($subject);
        }

        $this->command->info('Subject seeder berhasil dijalankan');
    }
}

Buat seeder untuk mahasiswa yang lebih kompleks:

php artisan make:seeder StudentSeeder

Isi database/seeders/StudentSeeder.php:

<?php

namespace Database\Seeders;

use App\Models\Student;
use App\Models\Subject;
use Illuminate\Database\Seeder;

class StudentSeeder extends Seeder
{
    public function run()
    {
        $students = [
            ['nim' => '2411533001', 'name' => 'Ahmad Rizki', 'address' => 'Jalan Merpati No. 5', 'major_id' => 1],
            ['nim' => '2411533002', 'name' => 'Budi Santoso', 'address' => 'Jalan Anggrek No. 10', 'major_id' => 1],
            ['nim' => '2411533003', 'name' => 'Citra Dewi', 'address' => 'Jalan Melati No. 7', 'major_id' => 2],
            ['nim' => '2411533004', 'name' => 'Doni Hermawan', 'address' => 'Jalan Mawar No. 3', 'major_id' => 2],
            ['nim' => '2411533005', 'name' => 'Eka Putri', 'address' => 'Jalan Dahlia No. 8', 'major_id' => 3],
        ];

        foreach ($students as $studentData) {
            $student = Student::create($studentData);
            
            // Assign mata kuliah secara random (2-4 mata kuliah per mahasiswa)
            $subjects = Subject::inRandomOrder()->take(rand(2, 4))->pluck('id');
            $student->subjects()->attach($subjects);
        }

        $this->command->info('Student seeder berhasil dijalankan');
    }
}

Daftarkan ketiga seeder di database/seeders/DatabaseSeeder.php:

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

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

Jalankan seeder untuk mengisi database dengan data dummy:

php artisan db:seed

8. Membuat Controller untuk Mengelola Data Relasi

Buat controller untuk menampilkan data mahasiswa dengan relasi:

php artisan make:controller StudentController

Buka app/Http/Controllers/StudentController.php dan implementasikan method index dengan eager loading:

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

    public function store(Request $request)
    {
        $student = Student::create($request->only(['nim', 'name', 'address', 'major_id']));
        
        // Attach mata kuliah ke mahasiswa
        if ($request->has('subjects')) {
            $student->subjects()->attach($request->subjects);
        }

        return redirect()->route('students.index')->with('success', 'Mahasiswa berhasil ditambahkan');
    }

    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);
        $student->update($request->only(['nim', 'name', 'address', 'major_id']));
        
        // Sync mata kuliah (menghapus yang tidak ada, menambah yang baru)
        if ($request->has('subjects')) {
            $student->subjects()->sync($request->subjects);
        }

        return redirect()->route('students.index')->with('success', 'Mahasiswa berhasil diubah');
    }

    public function destroy($id)
    {
        $student = Student::findOrFail($id);
        $student->delete();

        return redirect()->route('students.index')->with('success', 'Mahasiswa berhasil dihapus');
    }
}

Controller Implementation


9. Konfigurasi Routes

Daftarkan route resource untuk StudentController di routes/web.php:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\StudentController;

Route::get('/', function () {
    return view('welcome');
});

Route::resource('students', StudentController::class);

10. Membuat View untuk Menampilkan Data

Buat folder resources/views/students dan buat file index.blade.php untuk menampilkan daftar mahasiswa:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Daftar Mahasiswa</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container py-5">
        <h1 class="mb-4">Daftar Mahasiswa</h1>
        
        <a href="{{ route('students.create') }}" class="btn btn-primary mb-3">Tambah Mahasiswa</a>

        <div class="table-responsive">
            <table class="table table-striped table-hover">
                <thead class="table-dark">
                    <tr>
                        <th>NIM</th>
                        <th>Nama</th>
                        <th>Program Studi</th>
                        <th>Mata Kuliah</th>
                        <th>Total SKS</th>
                        <th>Aksi</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach($students as $student)
                    <tr>
                        <td><strong>{{ $student->nim }}</strong></td>
                        <td>{{ $student->name }}</td>
                        <td>{{ $student->major->name }}</td>
                        <td>
                            @foreach($student->subjects as $subject)
                                <span class="badge bg-info">{{ $subject->name }}</span>
                            @endforeach
                        </td>
                        <td><strong>{{ $student->subjects->sum('sks') }}</strong></td>
                        <td>
                            <a href="{{ route('students.edit', $student->id) }}" class="btn btn-sm btn-warning">Edit</a>
                            <form action="{{ route('students.destroy', $student->id) }}" method="POST" style="display:inline;">
                                @csrf
                                @method('DELETE')
                                <button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Yakin?')">Hapus</button>
                            </form>
                        </td>
                    </tr>
                    @endforeach
                </tbody>
            </table>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View Index Mahasiswa


11. Membuat View Create untuk Menambah Mahasiswa

Buat file resources/views/students/create.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tambah Mahasiswa</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container py-5">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <h1 class="mb-4">Tambah Mahasiswa Baru</h1>

                <form action="{{ route('students.store') }}" method="POST">
                    @csrf
                    
                    <div class="mb-3">
                        <label class="form-label">NIM</label>
                        <input type="text" name="nim" class="form-control" required>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Nama Lengkap</label>
                        <input type="text" name="name" class="form-control" required>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Alamat</label>
                        <textarea name="address" class="form-control" rows="3" required></textarea>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Program Studi</label>
                        <select name="major_id" class="form-select" required>
                            <option value="">Pilih Program Studi</option>
                            @foreach($majors as $major)
                                <option value="{{ $major->id }}">{{ $major->name }}</option>
                            @endforeach
                        </select>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Mata Kuliah</label>
                        <div>
                            @foreach($subjects as $subject)
                                <div class="form-check">
                                    <input type="checkbox" name="subjects[]" value="{{ $subject->id }}" class="form-check-input" id="subject_{{ $subject->id }}">
                                    <label class="form-check-label" for="subject_{{ $subject->id }}">
                                        {{ $subject->name }} ({{ $subject->sks }} SKS)
                                    </label>
                                </div>
                            @endforeach
                        </div>
                    </div>

                    <button type="submit" class="btn btn-success">Simpan</button>
                    <a href="{{ route('students.index') }}" class="btn btn-secondary">Batal</a>
                </form>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View Create Mahasiswa


12. Menjalankan dan Menguji Aplikasi

Jalankan development server Laravel:

php artisan serve

Akses aplikasi di browser melalui http://127.0.0.1:8000/students. Anda akan melihat daftar mahasiswa dengan data program studi dan mata kuliah yang terhubung melalui relasi database.

Uji fitur untuk menambah mahasiswa baru, edit data, dan hapus data untuk memastikan relasi bekerja dengan baik. Tampilan Akhir Aplikasi

13. Latihan & Tugas

Membuat halaman untuk menampilkan :

1. Semua mahasiswa beserta jurusan dan mata kuliahnya
2. Jurusan yang memiliki mahasiswa terbanyak
3. Mata kuliah yang diambil oleh mahasiswa tertentu
4. Total SKS yang diambil setiap mahasiswa
                                
Tampilan Akhir Aplikasi

Kesimpulan

Melalui praktikum implementasi Relationship dalam Laravel, telah berhasil dipelajari dan diterapkan konsep-konsep penting dalam mengelola data relasional dengan framework modern.

  • Migration dengan Foreign Key: Pemahaman mendalam tentang cara mendefinisikan hubungan antar tabel melalui file migration dan constraint cascade delete untuk menjaga integritas data.
  • Eloquent ORM: Penggunaan method-method Eloquent seperti hasMany(), belongsTo(), dan belongsToMany() membuat pengelolaan relasi menjadi jauh lebih mudah dibandingkan menulis query SQL manual.
  • Eager Loading: Teknik with() berhasil mengatasi N+1 problem dan meningkatkan performa aplikasi secara signifikan dengan mengurangi jumlah database query.
  • Manajemen Many-to-Many: Method attach() dan sync() memberikan cara yang elegant untuk mengelola relasi kompleks tanpa perlu manipulasi manual tabel pivot.
  • View dengan Blade Template: Blade template memudahkan penampilan data berelasi dengan syntax yang readable dan intuitif melalui akses properti relasional.

Penguasaan konsep relationship di Laravel adalah fondasi penting untuk membangun aplikasi web yang lebih kompleks dengan struktur data yang terorganisir dan efisien. Dengan pemahaman ini, developer siap menghadapi tantangan dalam implementasi sistem informasi skala menengah hingga besar.