Laravel 12 Tutorial: File Listing and Delete Functionality

Laravel 12 Tutorial: File Listing and Delete Functionality

Laravel 12 Tutorial: File Listing and Delete Functionality

In this tutorial, we’ll walk through building a robust file upload and management system using Laravel, including:

  • Uploading multiple files

  • Storing metadata in the database

  • Listing files using DataTables

  • Supporting download and delete actions

  • Enforcing permissions based on user roles

Route Definitions

Define your upload-related routes in web.php using a Controller group:

// ------------------------- Form Upload ----------------------------// Route::controller(FormController::class)->group(function () { Route::middleware('auth')->group(function () { Route::get('form/upload/page', 'index')->name('form/upload/page'); // Show upload form Route::post('form/upload/save', 'storeFileUpload')->name('form/upload/save'); // Handle upload Route::get('form/upload/listing', 'showFiles')->name('form/upload/listing'); // Show uploaded files Route::get('form/file/listing', 'getData')->name('get-data-file.listing'); // DataTables JSON Route::get('/download/{filename}', 'download')->name('file.download'); // Download a file Route::post('delete-file', 'destroy')->name('delete-file'); // Delete a file }); });

File Listing Blade View

Inside resources/views/form/listing.blade.php:

@extends('layouts.master') @section('content') <div class="row"> <div class="col-lg-12 mx-auto"> <div class="d-flex justify-content-between mb-3"> <div class="fw-bold">File Listing</div> <div> <a href="{{ route('home') }}" class="fw-semibold text-decoration-none">Dashboard</a> </div> </div> <div class="card p-3 shadow-sm"> <div class="table-responsive"> <table id="fileListing" class="table table-striped nowrap w-100"> <thead> <tr> <th>Actions</th> <th>No</th> <th>File Name</th> <th>Upload Name</th> <th>Date Uploaded</th> </tr> </thead> <tbody></tbody> </table> </div> </div> </div> </div> <!-- Delete Modal --> <div class="modal fade" id="modalDeleteFile" tabindex="-1"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <form action="{{ route('delete-file') }}" method="POST"> @csrf <div class="modal-header"> <h5 class="modal-title">Delete File</h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body text-center"> Are you sure you want to delete <strong id="d_name" class="text-danger"></strong>? </div> <input type="hidden" id="d_filename" name="filename"> <div class="modal-footer justify-content-center"> <button type="button" class="btn btn-outline-primary" data-bs-dismiss="modal">Cancel</button> <button type="submit" class="btn btn-outline-danger">Delete</button> </div> </form> </div> </div> </div> @endsection @section('script') <script> $(function() { const table = $('#fileListing').DataTable({ lengthMenu: [[10, 25, 50, 100], [10, 25, 50, 100]], buttons: ['pageLength'], pageLength: 10, order: [[4, 'desc']], scrollX: true, processing: true, serverSide: true, ajax: "{{ route('get-data-file.listing') }}", columns: [ { data: 'action', orderable: false, searchable: false }, { data: 'id' }, { data: 'filename' }, { data: 'upload_name' }, { data: 'uploaded_at' }, ] }); $(document).on('click', '.fileDelete', function() { const filename = $(this).data('filename'); $('#d_filename').val(filename); $('#d_name').text(filename); $('#modalDeleteFile').modal('show'); }); }); </script> @endsection

Controller Logic

Your FormController.php handles all the backend logic:

namespace App\Http\Controllers; use Illuminate\Support\Facades\{Storage, Auth, Log}; use Illuminate\Http\Request; use App\Models\Upload; use Carbon\Carbon; use Exception; class FormController extends Controller { public function showFiles() { return view('form.fileslisting'); } public function getData(Request $request) { $query = Upload::query(); $total = $query->count(); $search = $request->get('search')['value']; if ($search) { $query->where(function($q) use ($search) { $q->orWhere('filename', 'like', "%$search%") ->orWhere('upload_name', 'like', "%$search%") ->orWhere('uploaded_at', 'like', "%$search%"); }); } $filtered = $query->count(); $records = $query->orderBy( $request->get('columns')[$request->get('order')[0]['column']]['data'], $request->get('order')[0]['dir'] ) ->skip($request->get('start')) ->take($request->get('length')) ->get(); $userRole = Auth::user()->role_name; $permissions = config('roles')[$userRole] ?? []; $data = $records->map(function ($item, $index) use ($request, $permissions) { return [ 'action' => in_array('delete', $permissions) ? '<button class="btn btn-danger btn-sm fileDelete" data-filename="'.$item->filename.'"><i class="bi bi-trash"></i></button>' : '', 'id' => $request->get('start') + $index + 1, 'filename' => '<a href="'.route('file.download', $item->filename).'" class="filename" data-filename="'.$item->filename.'">'.$item->filename.'</a>', 'upload_name' => $item->upload_name, 'uploaded_at' => $item->uploaded_at, ]; }); return response()->json([ "draw" => intval($request->get('draw')), "iTotalRecords" => $total, "iTotalDisplayRecords" => $filtered, "aaData" => $data ]); } public function download($filename) { $path = "uploads/$filename"; if (!Storage::disk('public')->exists($path)) { abort(404); } return Storage::disk('public')->download($path); } public function destroy(Request $request) { try { $file = Upload::where('filename', $request->filename)->firstOrFail(); Storage::disk('public')->delete('uploads/' . $file->filename); $file->delete(); return back()->with('success', 'File deleted successfully.'); } catch (Exception $e) { Log::error('Delete error: '.$e->getMessage()); return back()->with('error', 'Failed to delete file.'); } } }

Upload Model Example

Ensure you have the Upload model like so:

namespace App\Models; use Illuminate\Database\Eloquent\Model; class Upload extends Model { protected $fillable = [ 'filename', 'upload_name', 'uploaded_at' ]; public $timestamps = false; }

Final Notes

  • Role permissions are assumed to be configured in config/roles.php

  • Bootstrap 5 and jQuery DataTables are used for UI

  • File validation ensures safe formats and size limits

Demo Features

FeatureDescription
UploadMultiple file upload with validation
ListingPaginated & searchable DataTable
DeleteSoft-confirmation via modal
DownloadDirect secure download from public disk
PermissionsRole-based button visibility
Souy Soeng

Souy Soeng

Hi there 👋, I’m Soeng Souy (StarCode Kh)
-------------------------------------------
🌱 I’m currently creating a sample Laravel and React Vue Livewire
👯 I’m looking to collaborate on open-source PHP & JavaScript projects
💬 Ask me about Laravel, MySQL, or Flutter
⚡ Fun fact: I love turning ☕️ into code!

Post a Comment

CAN FEEDBACK
close