🎯 Tujuan Pembelajaran
Di materi ini, diharapkan pembaca mampu:
- Menambahkan fitur upload gambar pada form tambah dan edit produk di Laravel.
- Memahami alur upload file di Laravel, mulai dari menerima input file, validasi, menyimpan, hingga menampilkannya kembali.
- Melakukan validasi file termasuk tipe file (image), ukuran maksimal, serta keamanan dasar dalam proses upload.
- Menyimpan file secara aman ke folder
public/storage/productsmenggunakanstore()bawaan Laravel. - Menyimpan nama file ke database melalui kolom
imagepada tabelproducts.
1. Memahami Alur Upload File di Laravel
Sebelum menulis kode, penting memahami alur teknis upload file di Laravel:
Request
File dikirim dari form menggunakan multipart/form-data, dan Laravel menyiapkan objek file di $request->file('image').
Validasi
Rule image memastikan file adalah gambar (jpg, jpeg, png, gif, svg, webp).
Rule max membatasi ukuran file dalam kilobytes.
Store / Penyimpanan File
Fungsi store() digunakan untuk:
- membuat nama file unik otomatis,
- mencegah file tertimpa,
- memastikan file berada di folder yang sesuai konfigurasi.
Menyimpan Nama File ke Database
Yang disimpan bukan file-nya, tetapi nama file (path) agar bisa ditampilkan kembali.
Menampilkan Gambar
Gambar dapat ditampilkan melalui asset('storage/...').
Dokumentasi Laravel:
📌 Filesystem Uploads: https://laravel.com/docs/11.x/filesystem#file-uploads 📌 Validation Rule Image: https://laravel.com/docs/11.x/validation#rule-image
2. Konfigurasi Storage (Dijalankan Sekali)
Folder storage/app/public tidak otomatis bisa diakses secara publik.
Jalankan perintah berikut:
php artisan storage:link
Penjelasan:
- Perintah ini membuat folder
public/storagesebagai symbolic link. - Semua file yang di-upload ke disk
publicakan tersedia melalui URLstorage/.... - Tanpa symbolic link ini, gambar tidak akan muncul meski upload berhasil.
3. Tambahkan Input File Pada Form Create & Edit
Dua aturan penting:
- Form wajib memakai
enctype="multipart/form-data". - Input harus
<input type="file">.
resources/views/products/create.blade.php
<form action="{{ route('products.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<!-- input lainnya -->
<div class="mb-3">
<label>Gambar Produk</label>
<input type="file" name="image" class="form-control">
</div>
<button class="btn btn-primary">Simpan</button>
</form>
resources/views/products/edit.blade.php
Biasanya form edit menampilkan gambar lama sebagai preview (opsional).
4. Controller: Store Produk + Upload Gambar
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required',
'price' => 'required|numeric',
'description' => 'nullable',
'stock' => 'nullable|integer',
'image' => 'nullable|image|max:2048', // validasi
]);
// Upload image jika ada
if ($request->hasFile('image')) {
$validated['image'] = $request->file('image')->store('products', 'public');
}
Product::create($validated);
return redirect()->route('products.index')->with('success', 'Produk berhasil ditambahkan');
}
Penjelasan:
imagememvalidasi file gambar.max:2048= maksimal 2MB.- Laravel membuat nama file hash agar menghindari duplikasi.
📌 Penjelasan Tambahan: Validasi Format File
Jika ingin membatasi ekstensi tertentu, seperti:
Hanya PNG
'image' => 'nullable|mimes:png|max:2048',
Hanya JPG/JPEG
'image' => 'nullable|mimes:jpg,jpeg|max:2048',
PNG + JPG
'image' => 'nullable|mimes:png,jpg,jpeg|max:2048',
5. Controller: Update Produk + Replace Gambar Lama
public function update(Request $request, Product $product)
{
$validated = $request->validate([
'name' => 'required',
'price' => 'required|numeric',
'description' => 'nullable',
'stock' => 'nullable|integer',
'image' => 'nullable|image|max:2048',
]);
if ($request->hasFile('image')) {
if ($product->image && \Storage::disk('public')->exists($product->image)) {
\Storage::disk('public')->delete($product->image);
}
$validated['image'] = $request->file('image')->store('products', 'public');
}
$product->update($validated);
return redirect()->route('products.index')->with('success', 'Produk berhasil diperbarui');
}
Kelebihan pola update ini:
- File lama tidak menumpuk.
- Upload baru hanya dilakukan jika user memilih gambar baru.
6. Controller: Hapus Produk + Hapus File
public function destroy(Product $product)
{
if ($product->image && \Storage::disk('public')->exists($product->image)) {
\Storage::disk('public')->delete($product->image);
}
$product->delete();
return redirect()->route('products.index')->with('success', 'Produk berhasil dihapus');
}
7. Menampilkan Gambar di Halaman Index
<td>
@if ($product->image)
<img src="{{ asset('storage/' . $product->image) }}" width="70">
@else
<small class="text-muted">Tidak ada gambar</small>
@endif
</td>
8. Ringkasan Keunggulan store()
✔ Nama file unik otomatis
✔ Menghindari overwrite
✔ Lebih aman
✔ Direkomendasikan oleh Laravel
✔ Struktur penyimpanan lebih rapi
📁 Struktur Folder Penting
📁 project-laravel/
├── 📁 app/
│ └── 📁 Http/
│ └── 📁 Controllers/
│ └── 📄 ProductController.php <-- Logika upload file & simpan nama gambar
│
├── 📁 public/
│ └── 📁 storage/
│ └── 📁 products/ <-- Hasil upload gambar (akses publik)
│
├── 📁 resources/
│ └── 📁 views/
│ └── 📁 products/
│ ├── 📄 create.blade.php <-- Form tambah produk + upload gambar
│ ├── 📄 edit.blade.php <-- Form edit produk + upload gambar
│ └── 📄 index.blade.php <-- Menampilkan daftar produk
│
├── 📁 routes/
│ └── 📄 web.php <-- Route CRUD termasuk delete
│
├── 📁 storage/
│ └── 📁 app/
│ └── 📁 public/
│ └── 📁 products/ <-- File asli sebelum di-link ke public
│