fbpx
Laravel Nova space guy

Delete a File After Downloading it With Laravel Nova Actions

Laravel Nova is a pretty great tool for configuring CRUD dashboards quickly and simply. We used it on a recent client project and have been thrilled with the results.

“Actions” are a nifty tool that comes with Nova for running tasks across one or more models. This particular project required running a dump of models in the database to a CSV. While there are a million ways of accomplishing this, it seemed appropriate to build it as a Nova action, allowing users to explicitly select the models they want to export at a given time.

When you run an action from the Nova dashboard, it fires off a request to the server and gets a response that tells the dashboard if the action was successful and if subsequent steps should be taken. This can be as simple as a toast notification, and as complicated as a file download.

The file download seemed like the ticket, but I didn’t really need the file to stick around. It could be tossed when the action had completed.

With a normal Laravel request, you can make use of streamed downloads to accomplish this – stream contents directly to the response. You don’t actually have to create a file. Alternatively, you can create a file and then delete it when the download has finished.

But Nova is a bit different. Actions have fixed responses they can deliver that the Nova dashboard will understand. Generally, they’re a simple array of JSON data. A typical Laravel download response isn’t something Nova knows how to handle, and the built-in download action response doesn’t have a way to handle streams or deleting a file when it finishes.

What we ended up doing was saving the file. Then rather than a download action response, we sent a redirect action response to another controller we defined with the filename attached. In that controller, we looked up the file and made use of that nifty deleteFileAfterSend method.

So our action looked like this:

/**
 * Perform the action on the given models.
 *
 * @param  \Laravel\Nova\Fields\ActionFields  $fields
 * @param  \Illuminate\Support\Collection  $models
 * @return mixed
 */
public function handle(ActionFields $fields, Collection $models)
{
    $time = time();
    $filename = "services-$time";

    $this->csv = Writer::createFromFileObject(new \SplTempFileObject());
    $this->insertHeaders();
    $models->each(function($location) {
        $this->csv->insertOne($location->toExport());
    });

    Storage::put($filename . '.csv', $this->csv->getContent());

    return Action::redirect( route('dump-download', [
        'file' => $filename,
    ] ) );
}Code language: PHP (php)

And then the lightweight controller we wired up:

public function show( $file, Request $request )
{
	$filename = $file . '.csv';
	$path = Storage::path( $filename );
	return response()->download( $path, $filename )->deleteFileAfterSend(true);
}Code language: PHP (php)

It’s not pretty, but it gets the job done. The alternative is…a cron job to clean up our storage folder once in a while? Yuck.

If you’ve found a more eloquent way of accomplishing this sort of thing, we’d love to hear about it! Drop a comment below.


Comments

2 responses to “Delete a File After Downloading it With Laravel Nova Actions”

  1. Neil Simpson Avatar
    Neil Simpson

    The Action::download() method simply returns a URL and filename for the download which is then appended to a newly created and subsequently destroyed DOM element. You could still pass the dump-download URL to this method and have the route handled as above.

  2. Leonardo Spuldar Avatar
    Leonardo Spuldar

    Thank you alot for this!

Leave a Reply

Your email address will not be published. Required fields are marked *