Add export for forms
This commit is contained in:
parent
5bd52e7b51
commit
917a3932e1
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form\Actions;
|
||||||
|
|
||||||
|
use App\Form\Models\Form;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use League\Csv\Writer;
|
||||||
|
use Lorisleiva\Actions\ActionRequest;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
|
||||||
|
class ExportAction
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle(Form $form): string
|
||||||
|
{
|
||||||
|
$csv = Writer::createFromString();
|
||||||
|
|
||||||
|
$csv->insertOne($form->getFields()->names());
|
||||||
|
|
||||||
|
foreach ($form->participants as $participant) {
|
||||||
|
$csv->insertOne($participant->getFields()->presentValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $csv->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asController(Form $form, ActionRequest $request): StreamedResponse
|
||||||
|
{
|
||||||
|
$contents = $this->handle($form);
|
||||||
|
|
||||||
|
$filename = 'tn-' . $form->slug . '.csv';
|
||||||
|
Storage::disk('temp')->put($filename, $contents);
|
||||||
|
|
||||||
|
return Storage::disk('temp')->download($filename);
|
||||||
|
}
|
||||||
|
}
|
|
@ -92,6 +92,22 @@ class FieldCollection extends Collection
|
||||||
return $attributes->toArray();
|
return $attributes->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
public function names(): array
|
||||||
|
{
|
||||||
|
return $this->map(fn ($field) => $field->name)->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<int, string>
|
||||||
|
*/
|
||||||
|
public function presentValues(): array
|
||||||
|
{
|
||||||
|
return $this->map(fn ($field) => $field->presentRaw())->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
private function findBySpecialType(SpecialType $specialType): ?Field
|
private function findBySpecialType(SpecialType $specialType): ?Field
|
||||||
{
|
{
|
||||||
return $this->first(fn ($field) => $field->specialType === $specialType);
|
return $this->first(fn ($field) => $field->specialType === $specialType);
|
||||||
|
|
|
@ -51,7 +51,8 @@ class FormResource extends JsonResource
|
||||||
'update' => route('form.update', ['form' => $this->getModel()]),
|
'update' => route('form.update', ['form' => $this->getModel()]),
|
||||||
'destroy' => route('form.destroy', ['form' => $this->getModel()]),
|
'destroy' => route('form.destroy', ['form' => $this->getModel()]),
|
||||||
'is_dirty' => route('form.is-dirty', ['form' => $this->getModel()]),
|
'is_dirty' => route('form.is-dirty', ['form' => $this->getModel()]),
|
||||||
'frontend' => str(app(FormSettings::class)->registerUrl)->replace('{slug}', $this->slug)
|
'frontend' => str(app(FormSettings::class)->registerUrl)->replace('{slug}', $this->slug),
|
||||||
|
'export' => route('form.export', ['form' => $this->getModel()]),
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,7 @@
|
||||||
<ui-action-button tooltip="Bearbeiten" class="btn-warning" icon="pencil" @click.prevent="edit(form)"></ui-action-button>
|
<ui-action-button tooltip="Bearbeiten" class="btn-warning" icon="pencil" @click.prevent="edit(form)"></ui-action-button>
|
||||||
<ui-action-button tooltip="Teilnehmende anzeigen" class="btn-info" icon="user" @click.prevent="showParticipants(form)"></ui-action-button>
|
<ui-action-button tooltip="Teilnehmende anzeigen" class="btn-info" icon="user" @click.prevent="showParticipants(form)"></ui-action-button>
|
||||||
<ui-action-button :href="form.links.frontend" target="_BLANK" tooltip="zur Anmeldeseite" class="btn-info" icon="eye"></ui-action-button>
|
<ui-action-button :href="form.links.frontend" target="_BLANK" tooltip="zur Anmeldeseite" class="btn-info" icon="eye"></ui-action-button>
|
||||||
|
<ui-action-button :href="form.links.export" target="_BLANK" tooltip="als CSV exportieren" class="btn-info" icon="document"></ui-action-button>
|
||||||
<ui-action-button tooltip="Löschen" class="btn-danger" icon="trash" @click.prevent="deleting = form"></ui-action-button>
|
<ui-action-button tooltip="Löschen" class="btn-danger" icon="trash" @click.prevent="deleting = form"></ui-action-button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -19,6 +19,7 @@ use App\Invoice\Actions\InvoiceStoreAction;
|
||||||
use App\Course\Actions\CourseUpdateAction;
|
use App\Course\Actions\CourseUpdateAction;
|
||||||
use App\Dashboard\Actions\IndexAction as DashboardIndexAction;
|
use App\Dashboard\Actions\IndexAction as DashboardIndexAction;
|
||||||
use App\Efz\ShowEfzDocumentAction;
|
use App\Efz\ShowEfzDocumentAction;
|
||||||
|
use App\Form\Actions\ExportAction as ActionsExportAction;
|
||||||
use App\Form\Actions\FormDestroyAction;
|
use App\Form\Actions\FormDestroyAction;
|
||||||
use App\Form\Actions\FormIndexAction;
|
use App\Form\Actions\FormIndexAction;
|
||||||
use App\Group\Actions\GroupBulkstoreAction;
|
use App\Group\Actions\GroupBulkstoreAction;
|
||||||
|
@ -153,6 +154,7 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
||||||
|
|
||||||
// ------------------------------------ form -----------------------------------
|
// ------------------------------------ form -----------------------------------
|
||||||
Route::get('/formtemplate', FormtemplateIndexAction::class)->name('formtemplate.index');
|
Route::get('/formtemplate', FormtemplateIndexAction::class)->name('formtemplate.index');
|
||||||
|
Route::get('/form/{form}/export', ActionsExportAction::class)->name('form.export');
|
||||||
Route::get('/form', FormIndexAction::class)->name('form.index');
|
Route::get('/form', FormIndexAction::class)->name('form.index');
|
||||||
Route::patch('/form/{form}', FormUpdateAction::class)->name('form.update');
|
Route::patch('/form/{form}', FormUpdateAction::class)->name('form.update');
|
||||||
Route::delete('/form/{form}', FormDestroyAction::class)->name('form.destroy');
|
Route::delete('/form/{form}', FormDestroyAction::class)->name('form.destroy');
|
||||||
|
|
|
@ -52,6 +52,7 @@ class FormIndexActionTest extends FormTestCase
|
||||||
->assertInertiaPath('data.data.0.registration_from', '2023-05-06 04:00:00')
|
->assertInertiaPath('data.data.0.registration_from', '2023-05-06 04:00:00')
|
||||||
->assertInertiaPath('data.data.0.registration_until', '2023-04-01 05:00:00')
|
->assertInertiaPath('data.data.0.registration_until', '2023-04-01 05:00:00')
|
||||||
->assertInertiaPath('data.data.0.links.participant_index', route('form.participant.index', ['form' => $form]))
|
->assertInertiaPath('data.data.0.links.participant_index', route('form.participant.index', ['form' => $form]))
|
||||||
|
->assertInertiaPath('data.data.0.links.export', route('form.export', ['form' => $form]))
|
||||||
->assertInertiaPath('data.meta.links.store', route('form.store'))
|
->assertInertiaPath('data.meta.links.store', route('form.store'))
|
||||||
->assertInertiaPath('data.meta.links.formtemplate_index', route('formtemplate.index'))
|
->assertInertiaPath('data.meta.links.formtemplate_index', route('formtemplate.index'))
|
||||||
->assertInertiaPath('data.meta.templates.0.name', 'tname')
|
->assertInertiaPath('data.meta.templates.0.name', 'tname')
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature\Form;
|
||||||
|
|
||||||
|
use App\Form\Fields\TextField;
|
||||||
|
use App\Form\Models\Form;
|
||||||
|
use App\Form\Models\Participant;
|
||||||
|
use App\Form\Scopes\ParticipantFilterScope;
|
||||||
|
use App\Group;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class ParticipantExportActionTest extends FormTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function testItShowsParticipantsAndColumns(): void
|
||||||
|
{
|
||||||
|
Storage::fake('temp');
|
||||||
|
$this->login()->loginNami()->withoutExceptionHandling();
|
||||||
|
$form = Form::factory()
|
||||||
|
->has(Participant::factory()->data(['stufe' => 'Pfadfinder', 'vorname' => 'Max', 'select' => ['A', 'B']]))
|
||||||
|
->sections([
|
||||||
|
FormtemplateSectionRequest::new()->fields([
|
||||||
|
$this->textField('vorname')->name('Vorname'),
|
||||||
|
$this->checkboxesField('select')->name('Abcselect')->options(['A', 'B', 'C']),
|
||||||
|
$this->dropdownField('stufe')->name('Stufe')->options(['Wölfling', 'Jungpfadfinder', 'Pfadfinder']),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
->name('ZEM 2024')
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->get(route('form.export', ['form' => $form]))->assertDownload('tn-zem-2024.csv');
|
||||||
|
$contents = Storage::disk('temp')->get('tn-zem-2024.csv');
|
||||||
|
$this->assertTrue(str_contains($contents, 'Max'));
|
||||||
|
$this->assertTrue(str_contains($contents, 'A, B'));
|
||||||
|
$this->assertTrue(str_contains($contents, 'Pfadfinder'));
|
||||||
|
$this->assertTrue(str_contains($contents, 'Stufe'));
|
||||||
|
$this->assertTrue(str_contains($contents, 'Abcselect'));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue