Fix CSV exports (missing data, add id, column name clash)

This commit is contained in:
Julien Nahum 2024-02-23 10:50:35 +01:00
parent e64d0d5da2
commit e85e4df7fe
4 changed files with 61 additions and 19 deletions

View File

@ -16,7 +16,7 @@ class FormSubmissionExport implements FromArray, WithHeadingRow
$contentRow = []; $contentRow = [];
foreach ($submissionData as $i => $row) { foreach ($submissionData as $i => $row) {
if($i==0){ if($i==0){
$headingRow[] = array_keys($row); $headingRow[] = $this->cleanColumnNames(array_keys($row));
} }
$contentRow[] = array_values($row); $contentRow[] = array_values($row);
} }
@ -27,6 +27,13 @@ class FormSubmissionExport implements FromArray, WithHeadingRow
]; ];
} }
private function cleanColumnNames(array $columnNames): array
{
return collect($columnNames)->map(function ($columnName) {
return preg_replace('/\s\(.*\)/', '', $columnName);
})->toArray();
}
public function array(): array public function array(): array
{ {
return $this->submissionData; return $this->submissionData;

View File

@ -14,6 +14,7 @@ use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Vinkla\Hashids\Facades\Hashids;
class FormSubmissionController extends Controller class FormSubmissionController extends Controller
{ {
@ -25,29 +26,29 @@ class FormSubmissionController extends Controller
public function submissions(string $id) public function submissions(string $id)
{ {
$form = Form::findOrFail((int) $id); $form = Form::findOrFail((int)$id);
$this->authorize('view', $form); $this->authorize('view', $form);
return FormSubmissionResource::collection($form->submissions()->paginate(100)); return FormSubmissionResource::collection($form->submissions()->paginate(100));
} }
public function update(AnswerFormRequest $request, $id, $submissionId) public function update(AnswerFormRequest $request, $id, $submissionId)
{ {
$form = $request->form; $form = $request->form;
$this->authorize('update', $form); $this->authorize('update', $form);
$job = new StoreFormSubmissionJob($request->form, $request->validated()); $job = new StoreFormSubmissionJob($request->form, $request->validated());
$job->setSubmissionId($submissionId)->handle(); $job->setSubmissionId($submissionId)->handle();
$data = new FormSubmissionResource(FormSubmission::findOrFail($submissionId)); $data = new FormSubmissionResource(FormSubmission::findOrFail($submissionId));
return $this->success([ return $this->success([
'message' => 'Record successfully updated.', 'message' => 'Record successfully updated.',
'data' => $data 'data' => $data
]); ]);
} }
public function export(string $id) public function export(string $id)
{ {
$form = Form::findOrFail((int) $id); $form = Form::findOrFail((int)$id);
$this->authorize('view', $form); $this->authorize('view', $form);
$allRows = []; $allRows = [];
@ -56,23 +57,26 @@ class FormSubmissionController extends Controller
->outputStringsOnly() ->outputStringsOnly()
->setEmptyForNoValue() ->setEmptyForNoValue()
->showRemovedFields() ->showRemovedFields()
->showHiddenFields()
->useSignedUrlForFiles(); ->useSignedUrlForFiles();
$tmp = $formatter->getCleanKeyValue(); $allRows[] = [
$tmp['Create Date'] = date("Y-m-d H:i", strtotime($row['created_at'])); 'id' => Hashids::encode($row['id']),
$allRows[] = $tmp; 'created_at' => date("Y-m-d H:i", strtotime($row['created_at'])),
...$formatter->getCleanKeyValue()
];
} }
$csvExport = (new FormSubmissionExport($allRows)); $csvExport = (new FormSubmissionExport($allRows));
return Excel::download( return Excel::download(
$csvExport, $csvExport,
$form->slug.'-submission-data.csv', $form->slug . '-submission-data.csv',
\Maatwebsite\Excel\Excel::CSV \Maatwebsite\Excel\Excel::CSV
); );
} }
public function submissionFile($id, $fileName) public function submissionFile($id, $fileName)
{ {
$fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id).'/' $fileName = Str::of(PublicFormController::FILE_UPLOAD_PATH)->replace('?', $id) . '/'
.urldecode($fileName); . urldecode($fileName);
if (!Storage::exists($fileName)) { if (!Storage::exists($fileName)) {
return $this->error([ return $this->error([
@ -85,7 +89,7 @@ class FormSubmissionController extends Controller
} }
return redirect( return redirect(
Storage::temporaryUrl($fileName, now()->addMinute()) Storage::temporaryUrl($fileName, now()->addMinute())
); );
} }
} }

View File

@ -85,15 +85,35 @@ class FormSubmissionFormatter
public function getCleanKeyValue() public function getCleanKeyValue()
{ {
$data = $this->formData; $data = $this->formData;
$fields = ($this->showRemovedFields) ? array_merge($this->form->properties, $this->form->removed_properties) : $this->form->properties;
$fields = collect($this->form->properties);
$removeFields = collect($this->form->removed_properties)->map(function ($field) {
return [
...$field,
'removed' => true
];
});
if ($this->showRemovedFields) {
$fields = $fields->merge($removeFields);
}
$fields = $fields->filter(function ($field) {
return !in_array($field['type'],['nf-text', 'nf-code', 'nf-page-break', 'nf-divider', 'nf-image']);
})->values();
$returnArray = []; $returnArray = [];
foreach ($fields as &$field) { foreach ($fields as $field) {
$isRemoved = in_array($field['id'], array_column($this->form->removed_properties, 'id')) ?? false;
if($isRemoved){ if (in_array($field['id'],['nf-text', 'nf-code', 'nf-page-break', 'nf-divider', 'nf-image'])) {
continue;
}
if($field['removed'] ?? false) {
$field['name'] = $field['name']." (deleted)"; $field['name'] = $field['name']." (deleted)";
} }
// Add ID to avoid name clashes
$field['name'] = $field['name'].' ('.\Str::of($field['id']).')';
// If not present skip // If not present skip
if (!isset($data[$field['id']])) { if (!isset($data[$field['id']])) {
if ($this->setEmptyForNoValue) { if ($this->setEmptyForNoValue) {

View File

@ -71,9 +71,10 @@
>Display columns</a> >Display columns</a>
</p> </p>
<p class="text-right cursor-pointer text-xs uppercase"> <p class="text-right cursor-pointer text-xs uppercase">
<a <a v-if="!exportLoading"
@click.prevent="downloadAsCsv" href="#" @click.prevent="downloadAsCsv" href="#"
>Export as CSV</a> >Export as CSV</a>
<p v-else><loader class="w-3 h-3 text-blue-500" /></p>
</p> </p>
</div> </div>
</div> </div>
@ -136,6 +137,7 @@ export default {
properties: [], properties: [],
removed_properties: [], removed_properties: [],
displayColumns: {}, displayColumns: {},
exportLoading: false,
searchForm: useForm({ searchForm: useForm({
search: '' search: ''
}), }),
@ -184,6 +186,9 @@ export default {
watch: { watch: {
'form.id'() { 'form.id'() {
this.onFormChange() this.onFormChange()
},
'searchForm.search'() {
this.dataChanged()
} }
}, },
mounted() { mounted() {
@ -271,6 +276,10 @@ export default {
this.dataChanged() this.dataChanged()
}, },
downloadAsCsv() { downloadAsCsv() {
if (this.exportLoading) {
return
}
this.exportLoading = true
opnFetch(this.exportUrl, {responseType: "blob"}) opnFetch(this.exportUrl, {responseType: "blob"})
.then(blob => { .then(blob => {
const filename = `${this.form.slug}-${Date.now()}-submissions.csv` const filename = `${this.form.slug}-${Date.now()}-submissions.csv`
@ -284,6 +293,8 @@ export default {
window.URL.revokeObjectURL(url) window.URL.revokeObjectURL(url)
}).catch((error) => { }).catch((error) => {
console.error(error) console.error(error)
}).finally(() => {
this.exportLoading = false
}) })
} }
} }