Add children filter to participant index
continuous-integration/drone/push Build is passing Details

This commit is contained in:
philipp lang 2024-06-19 23:51:20 +02:00
parent 73089ae654
commit 1a5675634f
6 changed files with 52 additions and 39 deletions

View File

@ -6,6 +6,7 @@ use App\Form\Models\Form;
use App\Form\Models\Participant;
use App\Form\Resources\ParticipantResource;
use App\Form\Scopes\ParticipantFilterScope;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Pagination\LengthAwarePaginator;
use Lorisleiva\Actions\Concerns\AsAction;
@ -14,18 +15,32 @@ class ParticipantIndexAction
{
use AsAction;
/**
* @return HasMany<Participant>
*/
protected function getQuery(Form $form, ParticipantFilterScope $filter): HasMany
{
return $form->participants()->withFilter($filter)->withCount('children')->with('form');
}
/**
* @return LengthAwarePaginator<Participant>
*/
public function handle(Form $form, ParticipantFilterScope $filter): LengthAwarePaginator
{
return $form->participants()->withFilter($filter)->with('form')->paginate(15);
return $this->getQuery($form, $filter)->paginate(15);
}
public function asController(Form $form): AnonymousResourceCollection
public function asController(Form $form, ?int $parent = null): AnonymousResourceCollection
{
$filter = ParticipantFilterScope::fromRequest(request()->input('filter'));
return ParticipantResource::collection($this->handle($form, $filter))
->additional(['meta' => ParticipantResource::meta($form)]);
$data = match ($parent) {
null => $this->handle($form, $filter),
-1 => $this->getQuery($form, $filter)->where('parent_id', null)->get(),
default => $this->getQuery($form, $filter)->where('parent_id', $parent)->get(),
};
return ParticipantResource::collection($data)->additional(['meta' => ParticipantResource::meta($form)]);
}
}

View File

@ -25,6 +25,7 @@ class ParticipantResource extends JsonResource
...$this->getModel()->getFields()->present(),
'created_at' => $this->created_at->format('Y-m-d H:i:s'),
'created_at_display' => $this->created_at->format('d.m.Y'),
'children_count' => $this->children_count,
'links' => [
'destroy' => route('participant.destroy', ['participant' => $this->getModel()]),
]

View File

@ -22,7 +22,6 @@ class ParticipantFilterScope extends Filter
* @param array<string, mixed> $data
*/
public function __construct(
public ?int $parent = null,
public array $data = [],
) {
}
@ -45,14 +44,6 @@ class ParticipantFilterScope extends Filter
*/
public function apply(Builder $query): Builder
{
if ($this->parent === -1) {
$query = $query->whereNull('parent_id');
}
if (!is_null($this->parent) && $this->parent > 0) {
$query = $query->where('parent_id', $this->parent);
}
foreach ($this->data as $key => $value) {
if ($value === static::$nan) {
continue;

View File

@ -27,6 +27,7 @@ class ParticipantFactory extends Factory
{
return [
'data' => [],
'parent_id' => null,
];
}

View File

@ -163,7 +163,7 @@ Route::group(['middleware' => 'auth:web'], function (): void {
Route::delete('/formtemplate/{formtemplate}', FormtemplateDestroyAction::class)->name('formtemplate.destroy');
Route::post('/form', FormStoreAction::class)->name('form.store');
Route::patch('/form/{form}/meta', FormUpdateMetaAction::class)->name('form.update-meta');
Route::get('/form/{form}/participants', ParticipantIndexAction::class)->name('form.participant.index');
Route::get('/form/{form}/participants/{parent?}', ParticipantIndexAction::class)->name('form.participant.index');
Route::post('/form/{form}/is-dirty', IsDirtyAction::class)->name('form.is-dirty');
Route::delete('/participant/{participant}', ParticipantDestroyAction::class)->name('participant.destroy');
});

View File

@ -2,7 +2,6 @@
namespace Tests\Feature\Form;
use App\Form\Fields\CheckboxField;
use App\Form\Fields\TextField;
use App\Form\Models\Form;
use App\Form\Models\Participant;
@ -127,30 +126,6 @@ class ParticipantIndexActionTest extends FormTestCase
->assertJsonCount(4, 'data');
}
public function testItShowsOnlyRootMembers(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->create();
Participant::factory()->for($form)->count(2)
->has(Participant::factory()->count(3)->for($form), 'children')
->create();
$this->callFilter('form.participant.index', ['parent' => -1], ['form' => $form])->assertJsonCount(2, 'data');
$this->callFilter('form.participant.index', ['parent' => null], ['form' => $form])->assertJsonCount(8, 'data');
}
public function testItShowsChildrenOfParent(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->create();
$parents = Participant::factory()->for($form)->count(2)
->has(Participant::factory()->count(3)->for($form), 'children')
->create();
$this->callFilter('form.participant.index', ['parent' => $parents->get(0)->id], ['form' => $form])->assertJsonCount(3, 'data');
$this->callFilter('form.participant.index', ['parent' => $parents->get(1)->id], ['form' => $form])->assertJsonCount(3, 'data');
}
public function testItPresentsNamiField(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
@ -191,4 +166,34 @@ class ParticipantIndexActionTest extends FormTestCase
->assertJsonPath('meta.columns.1.id', 'created_at')
->assertJsonPath('meta.columns.1.display_attribute', 'created_at_display');
}
public function testItShowsOnlyParentParticipantsWhenFilterEnabled(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->create();
$participant = Participant::factory()
->has(Participant::factory()->for($form)->count(2), 'children')
->for($form)
->create();
$this->callFilter('form.participant.index', [], ['form' => $form])->assertJsonCount(3, 'data');
$this->callFilter('form.participant.index', [], ['form' => $form, 'parent' => -1])->assertJsonCount(1, 'data');
$this->callFilter('form.participant.index', [], ['form' => $form, 'parent' => $participant->id])->assertJsonCount(2, 'data');
}
public function testItShowsChildrenCount(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->create();
$participant = Participant::factory()
->has(Participant::factory()->for($form)->count(2), 'children')
->for($form)
->create();
Participant::factory()->for($form)->create();
$this->callFilter('form.participant.index', [], ['form' => $form, 'parent' => -1])
->assertJsonPath('data.0.children_count', 2)
->assertJsonPath('data.1.children_count', 0);
$this->callFilter('form.participant.index', [], ['form' => $form, 'parent' => $participant->id])->assertJsonPath('data.0.children_count', 0);
}
}