Skip to main content

📁 Standar Upload File Laravel

Dokumentasi Penggunaan Trait HasFileUpload


1. Tujuan

Dokumentasi ini menjelaskan standar upload file di seluruh project Laravel, menggunakan trait HasFileUpload. Tujuannya agar seluruh proses upload file konsisten, aman, dan mudah dipelihara.


2. Struktur Trait

Trait ini menyediakan tiga fungsi utama:

  • uploadSingleFile: Upload satu file ke folder tertentu.
  • uploadMultipleFiles: Upload banyak file ke satu folder.
  • uploadDynamicFiles: Upload file dinamis untuk kebutuhan form builder/table.

Catatan:

  • Penamaan folder/file tidak diubah oleh trait.
  • Tidak ada prefix tambahan pada path folder.
  • Mendukung validasi tipe file (opsional).
  • Mendukung penghapusan file lama (opsional).
  • Mendukung error reporting ke Sentry.

3. Cara Menggunakan

3.1. Import Trait

use App\Traits\HasFileUpload;

3.2. Tambahkan Trait ke Controller

class MyController extends Controller
{
use HasFileUpload;
// ...
}

3.3. Upload Satu File

Fungsi ini akan mengembalikan sebuah array yang berisi path file jika berhasil, atau false jika gagal.

$storagePath = 'assets/configurations';
$allowedTypes = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/gif' => 'gif'
];

$uploadResult = $this->uploadSingleFile(
$request->file('setting_value'),
$storagePath,
$allowedTypes
// $filename, $oldFilePath, $disk bisa dikosongkan jika tidak perlu
);

if ($uploadResult) {
// Simpan path ke database
$filePath = $uploadResult['path'];
// $model->file_column = $filePath;
// $model->save();
} else {
// Handle error
}

Parameter

  • $file: Instance UploadedFile dari request.
  • $storagePath: Path folder tujuan (tanpa prefix tambahan).
  • $allowedTypes: (Opsional) Array tipe file yang diizinkan.
  • $filename: (Opsional) Nama file custom.
  • $oldFilePath: (Opsional) Path file lama yang ingin dihapus.
  • $disk: (Opsional) Nama disk Laravel (default: dari env FILESYSTEM_DISK atau public).

3.4. Upload Banyak File

$urls = $this->uploadMultipleFiles(
$request->file('files'),
"cdn/case_image/files/$data_id",
[
'image/png' => 'png',
'image/jpeg' => 'jpg',
'application/pdf' => 'pdf'
]
// $disk bisa dikosongkan jika tidak perlu
);
// $urls = array berisi hasil upload untuk setiap file

3.5. Upload Dinamis (Form Builder)

$this->uploadDynamicFiles(
$files, // array file dari form builder
$dataId, // id data
$keyRow, // array key row
['image/png', 'image/jpeg', 'application/pdf']
// $disk bisa dikosongkan jika tidak perlu
);

4. Standar Penamaan & Struktur Folder

  • Jangan ubah struktur folder yang sudah ada.
  • Gunakan path sesuai kebutuhan bisnis, misal:
    • assets/configurations/
    • cdn/case_image/files/{data_id}/
    • cdn/migrasi_izin_oss/file_evidence/{year}/{month}/{day}/
  • Jangan menambah prefix seperti /uploads/ atau sejenisnya. Path yang disimpan di database adalah path relatif dari root disk.

5. Standar Validasi File

  • Selalu validasi tipe file menggunakan $allowedTypes untuk mencegah upload file berbahaya.
  • Jika file tidak valid, fungsi akan mengembalikan false dan log warning.

6. Standar Penghapusan File Lama

  • Jika ingin menghapus file lama saat update, kirimkan path file lama pada parameter $oldFilePath.
  • File lama akan dihapus otomatis sebelum file baru diupload.

7. Contoh Implementasi di Controller

Berikut adalah contoh implementasi pada AssetConfigurationController untuk proses update data yang memiliki file.

public function update(Request $request, $id)
{
// ... validasi request

$assetConfiguration = AssetConfiguration::findOrFail($id);
$dataToUpdate = $request->only(['setting_name', 'description']);

try {
$oldFilePath = $assetConfiguration->setting_value;

// Jika ada file baru yang di-upload
if ($request->hasFile('setting_value')) {
$storagePath = 'assets/configurations';
$allowedTypes = ['image/jpeg' => 'jpg', 'image/png' => 'png'];

// Panggil trait untuk upload
$uploadResult = $this->uploadSingleFile(
$request->file('setting_value'),
$storagePath,
$allowedTypes,
null,
$oldFilePath // Kirim path file lama untuk dihapus
);

if ($uploadResult) {
// Simpan path baru ke array data
$dataToUpdate['setting_value'] = $uploadResult['path'];
} else {
return back()->with('error', 'Gagal mengunggah file gambar.');
}
}

// Update data di database
$assetConfiguration->update($dataToUpdate);

return redirect()->route('admin.configuration.asset-configurations.index')
->with('success', 'Konfigurasi aset berhasil diperbarui.');

} catch (\Exception $e) {
report($e);
return redirect()->route('admin.configuration.asset-configurations.index')
->with('error', 'Gagal memperbarui konfigurasi aset.');
}
}

8. Cara Menampilkan File di Blade

8.1. Menggunakan Model Accessor (Cara yang Direkomendasikan)

Untuk menjaga konsistensi dan memusatkan logika URL, sangat disarankan membuat Accessor di dalam Model terkait. Accessor ini akan mengubah path yang tersimpan di database menjadi URL lengkap.

Contoh di AssetConfiguration Model:

// App/Models/AssetConfiguration.php

/**
* Get full URL untuk setting_value berdasarkan ASSET_BASE_URL.
*
* @return string|null
*/
public function getSettingValueUrlAttribute(): ?string
{
if (!$this->setting_value) {
return null; // atau return URL gambar default
}
// Ambil base URL dari file .env
$baseUrl = rtrim(env('ASSET_BASE_URL'), '/') . '/';
// Gabungkan dengan path file dari database
return $baseUrl . ltrim($this->setting_value, '/');
}

Cara Pakai di Blade:

Cukup panggil nama accessor-nya (setting_value_url). Laravel akan otomatis menjalankan fungsi di atas.

{{-- $config adalah instance dari AssetConfiguration Model --}}
@if($config->setting_value_url)
<img src="{{ $config->setting_value_url }}" alt="{{ $config->setting_name }}" style="max-width: 100px;">
@else
<span>Tidak ada gambar</span>
@endif

8.2. Menggunakan Helper Storage (Alternatif)

Jika model tidak memiliki accessor khusus, Anda bisa menggunakan helper Storage bawaan Laravel. Pastikan konfigurasi FILESYSTEM_DISK di .env sudah benar.

{{-- $user->photo berisi path file, misal: 'assets/users/photo.jpg' --}}
<img src="{{ Storage::disk(env('FILESYSTEM_DISK', 'public'))->url($user->photo) }}" alt="User Photo">

{{-- Untuk link download --}}
<a href="{{ Storage::disk(env('FILESYSTEM_DISK', 'public'))->url($document->path) }}" target="_blank">
Download Dokumen
</a>

9. Best Practice

  • Selalu cek hasil upload. false berarti gagal, sedangkan array berisi path berarti berhasil.
  • Gunakan Model Accessor untuk membuat URL file agar logika terpusat dan mudah diubah.
  • Jangan hardcode path di view. Manfaatkan accessor atau helper Storage::url().
  • Jangan upload file ke folder root. Selalu gunakan subfolder sesuai kebutuhan bisnis.
  • Jangan lupa validasi file di sisi request (ukuran, tipe, dsb) sebelum memanggil trait.

10. Troubleshooting

  • Jika file tidak muncul di folder, cek permission folder storage/app/public (untuk local).
  • Jika file tidak bisa diakses dari browser, pastikan sudah menjalankan php artisan storage:link (untuk local).
  • Jika upload gagal, cek log di storage/logs/laravel.log dan dashboard Sentry.

11. Catatan Tambahan

  • Trait ini bisa dikembangkan untuk kebutuhan lain (resize image, watermark, dsb).
  • Jika ada kebutuhan khusus, update trait dan dokumentasi ini secara bersama-sama.

Dokumentasi ini WAJIB diikuti oleh semua developer untuk menjaga konsistensi dan keamanan upload file di seluruh aplikasi.