Skip to content

HARI 3: Database dan Eloquent ORM

Bootcamp Laravel - Sistem Pengelolaan Dokumen (SiDoku)


📋 Informasi Sesi

ItemKeterangan
Hari3 dari 5
Durasi8 Jam (09:00 - 17:00 WIB)
Topik UtamaDatabase, Migration, Eloquent ORM
ProjectSiDoku - Implementasi database

🎯 Learning Objectives

Setelah menyelesaikan sesi ini, peserta akan mampu:

  1. Memahami konsep database dan MySQL
  2. Membuat dan menjalankan Migration
  3. Menggunakan Seeder untuk data dummy
  4. Memahami dan menggunakan Eloquent ORM
  5. Membuat relasi antar model (One-to-Many, Many-to-Many)
  6. Melakukan operasi CRUD dengan Eloquent

SESI 1: Pengenalan Database di Laravel


1.1 Konfigurasi Database

Laravel mendukung berbagai database:

  • MySQL / MariaDB
  • PostgreSQL
  • SQLite
  • SQL Server

Konfigurasi di .env:

env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=sidoku
DB_USERNAME=root
DB_PASSWORD=

1.2 Membuat Database

Via Laragon HeidiSQL:

  1. Klik Laragon > Database > HeidiSQL
  2. Klik kanan > Create new > Database
  3. Nama: sidoku
  4. Charset: utf8mb4
  5. Collation: utf8mb4_unicode_ci

Via MySQL CLI:

sql
mysql -u root -p
CREATE DATABASE sidoku CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
SHOW DATABASES;
exit;

1.3 Test Koneksi

bash
php artisan db:show

atau

bash
php artisan tinker
DB::connection()->getPdo();

Jika tidak ada error, koneksi berhasil.


SESI 2: Migration


2.1 Pengenalan Migration

Migration adalah version control untuk database. Dengan migration, Anda dapat:

  • Membuat tabel secara programatik
  • Berbagi struktur database dengan tim
  • Rollback perubahan jika terjadi kesalahan

2.2 Membuat Migration

bash
php artisan make:migration create_kategoris_table

Hasil: database/migrations/2025_06_20_000000_create_kategoris_table.php

Edit migration:

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(): void
    {
        Schema::create('kategoris', function (Blueprint $table) {
            $table->id();
            $table->string('nama', 100);
            $table->string('kode', 20)->unique();
            $table->text('deskripsi')->nullable();
            $table->boolean('aktif')->default(true);
            $table->timestamps();
        });
    }

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

2.3 Tipe Data Column

MethodKeterangan
$table->id()Auto-increment primary key
$table->string('nama', 100)VARCHAR(100)
$table->text('deskripsi')TEXT
$table->integer('jumlah')INTEGER
$table->bigInteger('total')BIGINT
$table->float('nilai')FLOAT
$table->decimal('harga', 10, 2)DECIMAL(10,2)
$table->boolean('aktif')BOOLEAN/TINYINT(1)
$table->date('tanggal')DATE
$table->datetime('waktu')DATETIME
$table->timestamp('created_at')TIMESTAMP
$table->json('data')JSON
$table->enum('status', ['draft', 'aktif'])ENUM

Modifiers:

ModifierKeterangan
->nullable()Boleh NULL
->default('value')Nilai default
->unique()Harus unik
->unsigned()Tanpa negatif
->after('column')Posisi setelah column

2.4 Migration untuk Tabel Dokumen

bash
php artisan make:migration create_dokumens_table

Edit:

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(): void
    {
        Schema::create('dokumens', function (Blueprint $table) {
            $table->id();
            $table->foreignId('kategori_id')->constrained('kategoris')->onDelete('cascade');
            $table->foreignId('user_id')->constrained()->onDelete('cascade');
            $table->string('judul', 255);
            $table->string('nomor', 50)->unique();
            $table->text('deskripsi')->nullable();
            $table->string('file_path')->nullable();
            $table->enum('status', ['draft', 'pending', 'approved', 'rejected'])->default('draft');
            $table->date('tanggal_dokumen');
            $table->timestamps();
            $table->softDeletes();
        });
    }

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

2.5 Menjalankan Migration

bash
# Jalankan semua migration
php artisan migrate

# Lihat status migration
php artisan migrate:status

# Rollback migration terakhir
php artisan migrate:rollback

# Rollback semua dan migrate ulang
php artisan migrate:fresh

# Fresh dengan seeder
php artisan migrate:fresh --seed

2.6 Modifikasi Tabel

Menambah column:

bash
php artisan make:migration add_prioritas_to_dokumens_table
php
public function up(): void
{
    Schema::table('dokumens', function (Blueprint $table) {
        $table->enum('prioritas', ['rendah', 'sedang', 'tinggi'])
              ->default('sedang')
              ->after('status');
    });
}

public function down(): void
{
    Schema::table('dokumens', function (Blueprint $table) {
        $table->dropColumn('prioritas');
    });
}

SESI 3: Seeder dan Factory


3.1 Membuat Seeder

bash
php artisan make:seeder KategoriSeeder

Edit database/seeders/KategoriSeeder.php:

php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class KategoriSeeder extends Seeder
{
    public function run(): void
    {
        $kategoris = [
            [
                'nama' => 'Surat Keputusan',
                'kode' => 'SK',
                'deskripsi' => 'Surat keputusan resmi dari pimpinan',
                'aktif' => true,
                'created_at' => now(),
                'updated_at' => now(),
            ],
            [
                'nama' => 'Nota Dinas',
                'kode' => 'ND',
                'deskripsi' => 'Nota dinas internal',
                'aktif' => true,
                'created_at' => now(),
                'updated_at' => now(),
            ],
            [
                'nama' => 'Surat Tugas',
                'kode' => 'ST',
                'deskripsi' => 'Surat penugasan pegawai',
                'aktif' => true,
                'created_at' => now(),
                'updated_at' => now(),
            ],
            [
                'nama' => 'Surat Edaran',
                'kode' => 'SE',
                'deskripsi' => 'Surat edaran untuk informasi umum',
                'aktif' => true,
                'created_at' => now(),
                'updated_at' => now(),
            ],
        ];
        
        DB::table('kategoris')->insert($kategoris);
    }
}

3.2 Membuat Factory

bash
php artisan make:factory DokumenFactory

Edit database/factories/DokumenFactory.php:

php
<?php

namespace Database\Factories;

use App\Models\Kategori;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

class DokumenFactory extends Factory
{
    public function definition(): array
    {
        $kodeDokumen = ['SK', 'ND', 'ST', 'SE'];
        $kode = $this->faker->randomElement($kodeDokumen);
        
        return [
            'kategori_id' => Kategori::inRandomOrder()->first()?->id ?? 1,
            'user_id' => User::inRandomOrder()->first()?->id ?? 1,
            'judul' => $this->faker->sentence(4),
            'nomor' => $kode . '/' . $this->faker->unique()->numerify('###') . '/2025',
            'deskripsi' => $this->faker->paragraph(),
            'status' => $this->faker->randomElement(['draft', 'pending', 'approved', 'rejected']),
            'tanggal_dokumen' => $this->faker->dateTimeBetween('-1 year', 'now'),
        ];
    }
    
    // State untuk dokumen approved
    public function approved(): static
    {
        return $this->state(fn (array $attributes) => [
            'status' => 'approved',
        ]);
    }
    
    // State untuk dokumen pending
    public function pending(): static
    {
        return $this->state(fn (array $attributes) => [
            'status' => 'pending',
        ]);
    }
}

3.3 DatabaseSeeder

Edit database/seeders/DatabaseSeeder.php:

php
<?php

namespace Database\Seeders;

use App\Models\User;
use App\Models\Dokumen;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        // Buat user admin
        User::factory()->create([
            'name' => 'Admin SiDoku',
            'email' => 'admin@sidoku.test',
        ]);
        
        // Buat 10 user random
        User::factory(10)->create();
        
        // Jalankan KategoriSeeder
        $this->call([
            KategoriSeeder::class,
        ]);
        
        // Buat 50 dokumen random
        Dokumen::factory(50)->create();
        
        // Buat 10 dokumen approved
        Dokumen::factory(10)->approved()->create();
    }
}

3.4 Menjalankan Seeder

bash
# Jalankan DatabaseSeeder
php artisan db:seed

# Jalankan seeder tertentu
php artisan db:seed --class=KategoriSeeder

# Fresh migrate + seed
php artisan migrate:fresh --seed

SESI 4: Eloquent ORM


4.1 Pengenalan Eloquent

Eloquent adalah Object-Relational Mapping (ORM) bawaan Laravel yang memudahkan interaksi dengan database menggunakan model PHP.

Konvensi Penamaan:

ModelTabel Database
Userusers
Dokumendokumens
Kategorikategoris
DocumentCategorydocument_categories

4.2 Membuat Model

bash
# Model saja
php artisan make:model Kategori

# Model + Migration
php artisan make:model Kategori -m

# Model + Migration + Factory + Seeder + Controller
php artisan make:model Dokumen -mfsc

4.3 Model Kategori

app/Models/Kategori.php:

php
<?php

namespace App\Models;

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

class Kategori extends Model
{
    use HasFactory;
    
    // Nama tabel (jika tidak mengikuti konvensi)
    protected $table = 'kategoris';
    
    // Field yang bisa diisi mass assignment
    protected $fillable = [
        'nama',
        'kode',
        'deskripsi',
        'aktif',
    ];
    
    // Cast tipe data
    protected $casts = [
        'aktif' => 'boolean',
    ];
    
    // Relasi: Kategori memiliki banyak Dokumen
    public function dokumens(): HasMany
    {
        return $this->hasMany(Dokumen::class);
    }
    
    // Scope: Hanya kategori aktif
    public function scopeAktif($query)
    {
        return $query->where('aktif', true);
    }
}

4.4 Model Dokumen

app/Models/Dokumen.php:

php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;

class Dokumen extends Model
{
    use HasFactory, SoftDeletes;
    
    protected $table = 'dokumens';
    
    protected $fillable = [
        'kategori_id',
        'user_id',
        'judul',
        'nomor',
        'deskripsi',
        'file_path',
        'status',
        'prioritas',
        'tanggal_dokumen',
    ];
    
    protected $casts = [
        'tanggal_dokumen' => 'date',
    ];
    
    // Relasi: Dokumen milik satu Kategori
    public function kategori(): BelongsTo
    {
        return $this->belongsTo(Kategori::class);
    }
    
    // Relasi: Dokumen milik satu User
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
    
    // Accessor: Format tanggal Indonesia
    public function getTanggalIndonesiaAttribute(): string
    {
        return $this->tanggal_dokumen->translatedFormat('d F Y');
    }
    
    // Scope: Filter by status
    public function scopeStatus($query, $status)
    {
        return $query->where('status', $status);
    }
    
    // Scope: Pencarian
    public function scopeCari($query, $keyword)
    {
        return $query->where(function ($q) use ($keyword) {
            $q->where('judul', 'like', "%{$keyword}%")
              ->orWhere('nomor', 'like', "%{$keyword}%");
        });
    }
}

4.5 Operasi CRUD dengan Eloquent

Create (Insert)

php
// Cara 1: create() dengan mass assignment
$kategori = Kategori::create([
    'nama' => 'Surat Masuk',
    'kode' => 'SM',
    'deskripsi' => 'Surat masuk dari eksternal',
]);

// Cara 2: new + save
$dokumen = new Dokumen();
$dokumen->judul = 'SK Mutasi Pegawai';
$dokumen->nomor = 'SK/001/2025';
$dokumen->kategori_id = 1;
$dokumen->user_id = 1;
$dokumen->tanggal_dokumen = now();
$dokumen->save();

// Cara 3: firstOrCreate
$kategori = Kategori::firstOrCreate(
    ['kode' => 'SK'],
    ['nama' => 'Surat Keputusan', 'deskripsi' => 'SK']
);

Read (Select)

php
// Ambil semua data
$dokumens = Dokumen::all();

// Ambil dengan kondisi
$pending = Dokumen::where('status', 'pending')->get();

// Ambil satu data
$dokumen = Dokumen::find(1);
$dokumen = Dokumen::findOrFail(1); // Throw 404 jika tidak ada

// First
$first = Dokumen::where('status', 'approved')->first();

// Select kolom tertentu
$dokumens = Dokumen::select('id', 'judul', 'nomor')->get();

// Ordering
$dokumens = Dokumen::orderBy('created_at', 'desc')->get();

// Limit
$dokumens = Dokumen::take(10)->get();

// Pagination
$dokumens = Dokumen::paginate(15);

// Dengan relasi (Eager Loading)
$dokumens = Dokumen::with(['kategori', 'user'])->get();

Update

php
// Cara 1: find + save
$dokumen = Dokumen::find(1);
$dokumen->status = 'approved';
$dokumen->save();

// Cara 2: update langsung
Dokumen::where('id', 1)->update(['status' => 'approved']);

// Cara 3: updateOrCreate
Dokumen::updateOrCreate(
    ['nomor' => 'SK/001/2025'],
    ['judul' => 'SK Mutasi Updated', 'status' => 'pending']
);

Delete

php
// Cara 1: find + delete
$dokumen = Dokumen::find(1);
$dokumen->delete();

// Cara 2: destroy
Dokumen::destroy(1);
Dokumen::destroy([1, 2, 3]);

// Cara 3: delete dengan kondisi
Dokumen::where('status', 'draft')->delete();

// Soft Delete (jika menggunakan SoftDeletes)
$dokumen->delete(); // Set deleted_at

// Restore soft deleted
$dokumen = Dokumen::withTrashed()->find(1);
$dokumen->restore();

// Force delete (permanent)
$dokumen->forceDelete();

4.6 Query Builder Lanjutan

php
// Multiple conditions
$dokumens = Dokumen::where('status', 'approved')
    ->where('kategori_id', 1)
    ->orderBy('tanggal_dokumen', 'desc')
    ->get();

// Or condition
$dokumens = Dokumen::where('status', 'approved')
    ->orWhere('status', 'pending')
    ->get();

// Where In
$dokumens = Dokumen::whereIn('status', ['approved', 'pending'])->get();

// Where Between
$dokumens = Dokumen::whereBetween('tanggal_dokumen', ['2025-01-01', '2025-06-30'])->get();

// Where Null
$dokumens = Dokumen::whereNull('file_path')->get();

// Count
$total = Dokumen::where('status', 'approved')->count();

// Sum, Avg, Max, Min
$stats = Dokumen::selectRaw('
    COUNT(*) as total,
    SUM(CASE WHEN status = "approved" THEN 1 ELSE 0 END) as approved
')->first();

// Group By
$byKategori = Dokumen::selectRaw('kategori_id, COUNT(*) as total')
    ->groupBy('kategori_id')
    ->get();

SESI 5: Relasi Eloquent


5.1 Jenis Relasi

RelasiContoh
One to OneUser hasOne Profile
One to ManyKategori hasMany Dokumen
Many to OneDokumen belongsTo Kategori
Many to ManyDokumen belongsToMany Tag

5.2 One to Many

Kategori memiliki banyak Dokumen:

php
// Di Model Kategori
public function dokumens(): HasMany
{
    return $this->hasMany(Dokumen::class);
}

// Penggunaan
$kategori = Kategori::find(1);
$dokumens = $kategori->dokumens; // Collection of Dokumen

Dokumen milik satu Kategori:

php
// Di Model Dokumen
public function kategori(): BelongsTo
{
    return $this->belongsTo(Kategori::class);
}

// Penggunaan
$dokumen = Dokumen::find(1);
$namaKategori = $dokumen->kategori->nama;

5.3 Many to Many

Contoh: Dokumen dan Tag

Migration untuk pivot table:

bash
php artisan make:migration create_dokumen_tag_table
php
public function up(): void
{
    Schema::create('dokumen_tag', function (Blueprint $table) {
        $table->id();
        $table->foreignId('dokumen_id')->constrained('dokumens')->onDelete('cascade');
        $table->foreignId('tag_id')->constrained()->onDelete('cascade');
        $table->timestamps();
    });
}

Model Tag:

php
<?php

namespace App\Models;

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

class Tag extends Model
{
    protected $fillable = ['nama', 'slug'];
    
    public function dokumens(): BelongsToMany
    {
        return $this->belongsToMany(Dokumen::class, 'dokumen_tag');
    }
}

Di Model Dokumen:

php
public function tags(): BelongsToMany
{
    return $this->belongsToMany(Tag::class, 'dokumen_tag');
}

Operasi Many to Many:

php
// Attach tags ke dokumen
$dokumen = Dokumen::find(1);
$dokumen->tags()->attach([1, 2, 3]);

// Detach
$dokumen->tags()->detach([1, 2]);

// Sync (replace all)
$dokumen->tags()->sync([1, 3, 5]);

// Toggle
$dokumen->tags()->toggle([1, 2]);

// Ambil dokumen dengan tags
$dokumen = Dokumen::with('tags')->find(1);
foreach ($dokumen->tags as $tag) {
    echo $tag->nama;
}

5.4 Eager Loading

Menghindari N+1 query problem:

php
// [X] N+1 Problem (banyak query)
$dokumens = Dokumen::all();
foreach ($dokumens as $dok) {
    echo $dok->kategori->nama; // Query untuk setiap dokumen
}

// [OK] Eager Loading (hanya 2 query)
$dokumens = Dokumen::with('kategori')->get();
foreach ($dokumens as $dok) {
    echo $dok->kategori->nama; // Tidak ada query tambahan
}

// Multiple relations
$dokumens = Dokumen::with(['kategori', 'user', 'tags'])->get();

// Nested relations
$dokumens = Dokumen::with('kategori.dokumens')->get();

// Conditional eager loading
$dokumens = Dokumen::with(['kategori' => function ($query) {
    $query->where('aktif', true);
}])->get();

PRAKTIKUM: Implementasi Database SiDoku


Langkah 1: Buat Semua Migration

bash
php artisan make:migration create_kategoris_table
php artisan make:migration create_dokumens_table
php artisan make:migration create_tags_table
php artisan make:migration create_dokumen_tag_table

Langkah 2: Buat Model

bash
php artisan make:model Kategori -f
php artisan make:model Dokumen -f
php artisan make:model Tag -f

Langkah 3: Jalankan Migration dan Seeder

bash
php artisan migrate:fresh --seed

Langkah 4: Update Controller

app/Http/Controllers/DokumenController.php:

php
<?php

namespace App\Http\Controllers;

use App\Models\Dokumen;
use App\Models\Kategori;
use Illuminate\Http\Request;

class DokumenController extends Controller
{
    public function index(Request $request)
    {
        $query = Dokumen::with(['kategori', 'user']);
        
        // Filter by status
        if ($request->has('status')) {
            $query->where('status', $request->status);
        }
        
        // Search
        if ($request->has('search')) {
            $query->cari($request->search);
        }
        
        $dokumens = $query->orderBy('created_at', 'desc')->paginate(10);
        
        return view('dokumen.index', compact('dokumens'));
    }
    
    public function create()
    {
        $kategoris = Kategori::aktif()->get();
        return view('dokumen.create', compact('kategoris'));
    }
    
    public function store(Request $request)
    {
        $validated = $request->validate([
            'judul' => 'required|string|max:255',
            'nomor' => 'required|string|max:50|unique:dokumens',
            'kategori_id' => 'required|exists:kategoris,id',
            'deskripsi' => 'nullable|string',
            'tanggal_dokumen' => 'required|date',
        ]);
        
        $validated['user_id'] = auth()->id() ?? 1;
        $validated['status'] = 'draft';
        
        Dokumen::create($validated);
        
        return redirect()->route('dokumen.index')
            ->with('success', 'Dokumen berhasil ditambahkan!');
    }
    
    public function show(Dokumen $dokumen)
    {
        $dokumen->load(['kategori', 'user', 'tags']);
        return view('dokumen.show', compact('dokumen'));
    }
    
    public function edit(Dokumen $dokumen)
    {
        $kategoris = Kategori::aktif()->get();
        return view('dokumen.edit', compact('dokumen', 'kategoris'));
    }
    
    public function update(Request $request, Dokumen $dokumen)
    {
        $validated = $request->validate([
            'judul' => 'required|string|max:255',
            'nomor' => 'required|string|max:50|unique:dokumens,nomor,' . $dokumen->id,
            'kategori_id' => 'required|exists:kategoris,id',
            'deskripsi' => 'nullable|string',
            'tanggal_dokumen' => 'required|date',
        ]);
        
        $dokumen->update($validated);
        
        return redirect()->route('dokumen.index')
            ->with('success', 'Dokumen berhasil diupdate!');
    }
    
    public function destroy(Dokumen $dokumen)
    {
        $dokumen->delete();
        
        return redirect()->route('dokumen.index')
            ->with('success', 'Dokumen berhasil dihapus!');
    }
}

Langkah 5: Update View

resources/views/dokumen/index.blade.php:

html
@extends('layouts.app')

@section('title', 'Daftar Dokumen')

@section('content')
    <div class="bg-white rounded-lg shadow p-6">
        <div class="flex justify-between items-center mb-6">
            <h1 class="text-2xl font-bold">Daftar Dokumen</h1>
            <a href="{{ route('dokumen.create') }}" 
               class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
                + Tambah Dokumen
            </a>
        </div>
        
        {{-- Filter dan Search --}}
        <form method="GET" class="mb-6 flex gap-4">
            <input type="text" 
                   name="search" 
                   value="{{ request('search') }}"
                   placeholder="Cari judul atau nomor..."
                   class="border rounded px-3 py-2 w-64">
            
            <select name="status" class="border rounded px-3 py-2">
                <option value="">Semua Status</option>
                <option value="draft" {{ request('status') == 'draft' ? 'selected' : '' }}>Draft</option>
                <option value="pending" {{ request('status') == 'pending' ? 'selected' : '' }}>Pending</option>
                <option value="approved" {{ request('status') == 'approved' ? 'selected' : '' }}>Approved</option>
                <option value="rejected" {{ request('status') == 'rejected' ? 'selected' : '' }}>Rejected</option>
            </select>
            
            <button type="submit" class="bg-gray-500 text-white px-4 py-2 rounded">Filter</button>
        </form>
        
        {{-- Flash message --}}
        @if(session('success'))
            <x-alert type="success" :message="session('success')" />
        @endif
        
        {{-- Table --}}
        <table class="w-full border-collapse">
            <thead>
                <tr class="bg-gray-200">
                    <th class="border p-2 text-left">No</th>
                    <th class="border p-2 text-left">Nomor</th>
                    <th class="border p-2 text-left">Judul</th>
                    <th class="border p-2 text-left">Kategori</th>
                    <th class="border p-2 text-left">Status</th>
                    <th class="border p-2 text-left">Tanggal</th>
                    <th class="border p-2 text-left">Aksi</th>
                </tr>
            </thead>
            <tbody>
                @forelse($dokumens as $dok)
                    <tr class="hover:bg-gray-50">
                        <td class="border p-2">{{ $loop->iteration + ($dokumens->currentPage() - 1) * $dokumens->perPage() }}</td>
                        <td class="border p-2">{{ $dok->nomor }}</td>
                        <td class="border p-2">{{ $dok->judul }}</td>
                        <td class="border p-2">{{ $dok->kategori->nama ?? '-' }}</td>
                        <td class="border p-2">
                            <span class="px-2 py-1 rounded text-xs 
                                @if($dok->status == 'approved') bg-green-100 text-green-800
                                @elseif($dok->status == 'pending') bg-yellow-100 text-yellow-800
                                @elseif($dok->status == 'rejected') bg-red-100 text-red-800
                                @else bg-gray-100 text-gray-800
                                @endif">
                                {{ ucfirst($dok->status) }}
                            </span>
                        </td>
                        <td class="border p-2">{{ $dok->tanggal_dokumen->format('d/m/Y') }}</td>
                        <td class="border p-2">
                            <a href="{{ route('dokumen.show', $dok) }}" class="text-blue-500 hover:underline">Lihat</a>
                            <a href="{{ route('dokumen.edit', $dok) }}" class="text-yellow-500 hover:underline ml-2">Edit</a>
                            <form action="{{ route('dokumen.destroy', $dok) }}" method="POST" class="inline">
                                @csrf
                                @method('DELETE')
                                <button type="submit" 
                                        class="text-red-500 hover:underline ml-2"
                                        onclick="return confirm('Yakin hapus?')">Hapus</button>
                            </form>
                        </td>
                    </tr>
                @empty
                    <tr>
                        <td colspan="7" class="border p-4 text-center text-gray-500">
                            Belum ada dokumen
                        </td>
                    </tr>
                @endforelse
            </tbody>
        </table>
        
        {{-- Pagination --}}
        <div class="mt-4">
            {{ $dokumens->withQueryString()->links() }}
        </div>
    </div>
@endsection

✅ Checkpoint Hari 3

Pastikan Anda sudah bisa:

  • Membuat dan menjalankan migration
  • Menggunakan seeder dan factory
  • Membuat model dengan fillable, casts, dan relasi
  • Melakukan operasi CRUD dengan Eloquent
  • Menggunakan relasi One-to-Many dan Many-to-Many
  • Menggunakan eager loading untuk optimasi query

Selamat! Anda siap untuk Hari 4: Advanced Features dan API!


Referensi

Dibuat dengan ❤️ untuk ASN Indonesia