Export download prompt

https://filamentphp.com/docs/3.x/actions/prebuilt-actions/export Unless im blind, is there a way to click export, then prompt the ability for the user to download and save to their device, rather than saving in storage? As im assuming this is gonna require a separate link or button to doiwnload the exported file?...
18 Replies
lukevi
lukevi3mo ago
I would prefer this too - my exports are not large enough to justify the backgrounding & db-notification requirements
toeknee
toeknee3mo ago
No, the way the system is designed is for batch exporting not direct. It has performance in mind for bulk exporting. You could see if Dan would accept a PR for a new method: download() which runs the functions opposed to jobbing it and then downloads it directly. i.e. ->download(queue) or ->download(direct)
nowak
nowak3mo ago
I would love to see this too!
Jamie Cee
Jamie Cee3mo ago
Apologies for the delayed reply. Defo something useful, but would have to be something I'd have to gain time for.
toeknee
toeknee3mo ago
Dan is looking to add a direct() method possibility.
Jamie Cee
Jamie Cee3mo ago
direct? As in directing what to do with the export?
toeknee
toeknee3mo ago
A direct download type.
Jamie Cee
Jamie Cee3mo ago
Ah, yeah would be great. Just the naming of "direct" threw me off a little 🤣 But yeah, from a client using the cms POV, would be great to allow them to obtain the export
nowak
nowak3mo ago
Is there a PR or issue for this that we can follow?
toeknee
toeknee3mo ago
Not at present, I'll look to create one
nowak
nowak3mo ago
Thank you!
Jamie Cee
Jamie Cee2mo ago
@toeknee Were you in the progress of doing a PR for the ability to download an export?
toeknee
toeknee2mo ago
I didn't get round to it, so please feel free!
Jamie Cee
Jamie Cee2mo ago
Cool, Ill take a look in my spare time, Just randomly sprung to mind while at work
Mustafa_Dev
Mustafa_Dev4w ago
I was looking for this feature yesterday. So I think it's good to have.
Jamie Cee
Jamie Cee3w ago
I totally forgot to have a look into it ngl. Ill have to try find some time
ericmp
ericmp3w ago
agree ^^
Jamie Cee
Jamie Cee3w ago
So Im almost certain there has to be an easier way, but for now, I made a custom action, and implemented the Export functionality from ExportCsv class.
class ExportUsersAction extends Action
{
use CanExportRecords;
}
class ExportUsersAction extends Action
{
use CanExportRecords;
}
Inside the class above, I have this function:
/* Create the csv to download */
public function downloadCsv(Exporter $exporter, string $query, Collection $records, array $columnMap)
{
$exceptions = [];

$processedRows = 0;
$successfulRows = 0;

$csv = \League\Csv\Writer::createFromFileObject(new SplTempFileObject());
$csv->setDelimiter(',');

$query = EloquentSerializeFacade::unserialize($query);

foreach ($exporter->getCachedColumns() as $column) {
$column->applyRelationshipAggregates($query);
$column->applyEagerLoading($query);
}

$csv->insertOne(array_values($columnMap));

foreach ($records as $record) {
try {
$csv->insertOne(($exporter)($record));

$successfulRows++;
} catch (\Throwable $exception) {
$exceptions[$exception::class] = $exception;
}

$processedRows++;
}

// Return the CSV content as a downloadable response
// Create a StreamedResponse to output the CSV content
$response = new \Symfony\Component\HttpFoundation\StreamedResponse(function () use ($csv) {
echo $csv->toString();
});

// Set the headers to force download
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="data.csv"');

if ($response) {
/* Do we prompt the user to download */
Notification::make()
->title("Exporting CSV file")
->body("Exporting content to CSV file")
->success()
->duration(5000)
->send();
}

return $response;
}
/* Create the csv to download */
public function downloadCsv(Exporter $exporter, string $query, Collection $records, array $columnMap)
{
$exceptions = [];

$processedRows = 0;
$successfulRows = 0;

$csv = \League\Csv\Writer::createFromFileObject(new SplTempFileObject());
$csv->setDelimiter(',');

$query = EloquentSerializeFacade::unserialize($query);

foreach ($exporter->getCachedColumns() as $column) {
$column->applyRelationshipAggregates($query);
$column->applyEagerLoading($query);
}

$csv->insertOne(array_values($columnMap));

foreach ($records as $record) {
try {
$csv->insertOne(($exporter)($record));

$successfulRows++;
} catch (\Throwable $exception) {
$exceptions[$exception::class] = $exception;
}

$processedRows++;
}

// Return the CSV content as a downloadable response
// Create a StreamedResponse to output the CSV content
$response = new \Symfony\Component\HttpFoundation\StreamedResponse(function () use ($csv) {
echo $csv->toString();
});

// Set the headers to force download
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="data.csv"');

if ($response) {
/* Do we prompt the user to download */
Notification::make()
->title("Exporting CSV file")
->body("Exporting content to CSV file")
->success()
->duration(5000)
->send();
}

return $response;
}
And inside the setUp function, then inside $this->action() function, I call
return $action->downloadCsv($exporter, $serializedQuery, $records, $columnMap);
return $action->downloadCsv($exporter, $serializedQuery, $records, $columnMap);
Very unique to my case, so not ideal to use as a PR It does still populate the exports table, but doesn't run through the queue etc But I got lost navigating around things and finding where the best part to break it out would be, So if anyone does go and make a PR for the download feature, lemme know 😄