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
filesystemsdan membuat symlink storage. - Menambahkan kolom
photopada tabelassetsmelalui 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: โ
| Disk | Lokasi | Bisa Diakses Browser? |
|---|---|---|
local | storage/app/ | โ Tidak (privat) |
public | storage/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 โ
Step 1: Jalankan Storage Link โ
php artisan storage:linkSetelah berhasil, akan ada folder public/storage yang sebetulnya adalah shortcut ke storage/app/public/.
Step 2: Buat Migration Tambah Kolom photo โ
php artisan make:migration add_photo_to_assets_table --table=assetsEdit file migration yang baru dibuat:
// 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:
php artisan migrateStep 3: Update Model Asset โ
Tambahkan photo ke $fillable:
// 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:
- Atribut
enctype="multipart/form-data"pada tag<form>. - Input field untuk file.
{{-- 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 โ
// 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.