Skip to content

Day 21 โ€” Upload File: Konsep & Implementasi Dasar โ€‹

Fase: 3 โ€” Fitur Lanjutan | Minggu: 5 | Hari: Senin


๐ŸŽฏ Tujuan Hari Ini โ€‹

  • Memahami bagaimana file upload bekerja di Laravel secara teknis.
  • Mengkonfigurasi filesystems dan membuat symlink storage.
  • Menambahkan kolom photo pada tabel assets melalui migration baru.
  • Membuat form upload foto yang tervalidasi (tipe & ukuran).

๐Ÿ“– Penjelasan: Bagaimana File Upload Bekerja? โ€‹

Ketika user mengirim file melalui form HTML, browser mengirimkannya sebagai multipart/form-data โ€” berbeda dari form biasa yang hanya mengirim teks. Laravel menangani ini melalui object Illuminate\Http\UploadedFile yang dapat diakses via $request->file('nama_field').

Dua Disk Storage Utama Laravel: โ€‹

DiskLokasiBisa Diakses Browser?
localstorage/app/โŒ Tidak (privat)
publicstorage/app/public/โœ… Ya (via symlink)

Untuk foto aset yang perlu ditampilkan di web, gunakan disk public.

IMPORTANT

Kamu WAJIB menjalankan php artisan storage:link SATU KALI untuk membuat symlink dari public/storage โ†’ storage/app/public. Tanpa ini, file tidak bisa diakses dari browser.


๐Ÿ”ง Step-by-Step โ€‹

bash
php artisan storage:link

Setelah berhasil, akan ada folder public/storage yang sebetulnya adalah shortcut ke storage/app/public/.


Step 2: Buat Migration Tambah Kolom photo โ€‹

bash
php artisan make:migration add_photo_to_assets_table --table=assets

Edit file migration yang baru dibuat:

php
// database/migrations/xxxx_add_photo_to_assets_table.php

public function up(): void
{
    Schema::table('assets', function (Blueprint $table) {
        $table->string('photo')->nullable()->after('stock');
        // nullable() karena foto tidak wajib ada
    });
}

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

Jalankan migration:

bash
php artisan migrate

Step 3: Update Model Asset โ€‹

Tambahkan photo ke $fillable:

php
// app/Models/Asset.php

protected $fillable = [
    'name',
    'category_id',
    'stock',
    'condition',
    'photo',     // โ† tambahkan ini
    'description',
];

Step 4: Update Form di Blade (Tambah Foto) โ€‹

Pada form create/edit asset, tambahkan:

  1. Atribut enctype="multipart/form-data" pada tag <form>.
  2. Input field untuk file.
html
{{-- resources/views/assets/create.blade.php --}}

<form action="{{ route('assets.store') }}" method="POST" enctype="multipart/form-data">
    @csrf

    {{-- ... field lainnya ... --}}

    <div class="mb-3">
        <label for="photo" class="form-label">Foto Aset</label>
        <input
            type="file"
            class="form-control @error('photo') is-invalid @enderror"
            id="photo"
            name="photo"
            accept="image/*"
        >
        @error('photo')
            <div class="invalid-feedback">{{ $message }}</div>
        @enderror
        <div class="form-text">Format: JPG, PNG, WEBP. Maks. 2MB.</div>
    </div>

    <button type="submit" class="btn btn-primary">Simpan Aset</button>
</form>

NOTE

accept="image/*" hanya memfilter di sisi browser (UI). Validasi yang sesungguhnya tetap HARUS dilakukan di server (controller).


Step 5: Validasi & Simpan di Controller โ€‹

php
// app/Http/Controllers/AssetController.php

public function store(Request $request)
{
    $validated = $request->validate([
        'name'        => 'required|string|max:255',
        'category_id' => 'required|exists:categories,id',
        'stock'       => 'required|integer|min:0',
        'condition'   => 'required|in:good,damaged,lost',
        'description' => 'nullable|string',
        // Validasi file upload:
        'photo'       => 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048',
        //                          โ†‘         โ†‘                   โ†‘
        //                      harus gambar  tipe yg diizinkan   maks 2MB (dalam KB)
    ]);

    // Proses upload jika ada file
    if ($request->hasFile('photo')) {
        $path = $request->file('photo')->store('assets', 'public');
        // File akan disimpan di: storage/app/public/assets/namafile.jpg
        $validated['photo'] = $path;
    }

    Asset::create($validated);

    return redirect()->route('assets.index')
        ->with('success', 'Aset berhasil ditambahkan!');
}

๐Ÿงช Uji Coba Mandiri โ€‹

Setelah implementasi selesai, lakukan pengujian berikut:

  • [ ] Buka form tambah aset โ†’ upload foto โ†’ simpan โ†’ pastikan tidak ada error.
  • [ ] Cek folder storage/app/public/assets/ โ†’ apakah file foto tersimpan?
  • [ ] Coba upload file selain gambar (misal .pdf) โ†’ pastikan ada pesan error validasi.
  • [ ] Coba upload file lebih dari 2MB โ†’ pastikan ada pesan error validasi ukuran.

๐Ÿ“ Catatan Penting Hari Ini โ€‹

TIP

Method store() dari UploadedFile secara otomatis membuat nama file yang unik (menggunakan hash), sehingga tidak ada risiko nama file bentrok. Kamu tidak perlu membuat nama file sendiri kecuali ada kebutuhan khusus.

WARNING

Jangan pernah menggunakan nama file original dari user ($request->file('photo')->getClientOriginalName()). Ini adalah celah keamanan karena user bisa menamai file dengan karakter berbahaya.

Program Magang SMK RPL โ€” Rekayasa Perangkat Lunak (2 Bulan)