Search code examples
laraveldownloadlaravel-10

How to allow users to download a file in multiple views with Laravel 10?


Let's say I have an uploads.index.view.php and an uploads.show.view.php, which lead to the UploadController, which is a resource controller.

The index view shows a list of user-uploaded files as such:

Upload controller:

public function index() {
    return view('home', [
        'uploads' => Upload::paginate(20)
    ]);
}

Index view:

@foreach ($uploads as $upload)
<tr>
    <td class="table-uploaded table-td--center"><a href="#">{{$upload->user->name}}</a></td>
    <td class="table-cat table-td--center">{{$upload->category->category}}</td>
    @if ($upload->name)
    <td class="table-title"><a href="{{route('uploads.show', $upload->id)}}">{{$upload->name}}</a></td>
    @else
    <td class="table-title"><a href="{{route('uploads.show', $upload->id)}}">{{$upload->title}}</a></td>
    @endif
</tr>
@endforeach

And the show view shows a single upload's page as such:

public function show(Upload $upload) {
    return view('single', [
        'upload' => $upload
    ]);
}

The index should contain a <a href="DOWNLOAD LINK HERE">UPLOAD TITLE</a> and the single view contains a <a href="DOWNLOAD LINK HERE">Download</a>.

What's the most Eloquent way to have the browser download the corresponding $upload upon clicking any of the two links? Am I making a function inside of the index and show public functions in the UploadController, or a separate public function download() for the UploadController?

Would appreciate a detailed answer, including what to put in the <a></a> tags and the route, since I'm fairly new to this.


Solution

  • You could simply achieve it like this:

    Route:

    Route::get('/uploads/{upload}/download', 'UploadController@download')->name('uploads.download');
    

    In UploadController, add the download method. You can use Laravel's built-in download response to serve the file to the user.

    public function download(Upload $upload) {
        $filePath = storage_path('app/uploads/' . $upload->file_path);
        
        return response()->download($filePath, $upload->name);
    }
    

    Replace the placeholder "DOWNLOAD LINK HERE" with the actual route to the download method:

    <td class="table-title"><a href="{{ route('uploads.download', $upload->id) }}">{{$upload->name ?? $upload->title}}</a></td>
    

    Replace the placeholder "DOWNLOAD LINK HERE" with the actual route to the download method:

    <a href="{{ route('uploads.download', $upload->id) }}">Download</a>