diff --git a/app/Form/Actions/ParticipantIndexAction.php b/app/Form/Actions/ParticipantIndexAction.php index 3157405e..df779bdc 100644 --- a/app/Form/Actions/ParticipantIndexAction.php +++ b/app/Form/Actions/ParticipantIndexAction.php @@ -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 + */ + protected function getQuery(Form $form, ParticipantFilterScope $filter): HasMany + { + return $form->participants()->withFilter($filter)->withCount('children')->with('form'); + } + /** * @return LengthAwarePaginator */ 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)]); } } diff --git a/app/Form/Resources/ParticipantResource.php b/app/Form/Resources/ParticipantResource.php index c8ad10a2..b200242f 100644 --- a/app/Form/Resources/ParticipantResource.php +++ b/app/Form/Resources/ParticipantResource.php @@ -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()]), ] diff --git a/app/Form/Scopes/ParticipantFilterScope.php b/app/Form/Scopes/ParticipantFilterScope.php index 1b117764..38ab982e 100644 --- a/app/Form/Scopes/ParticipantFilterScope.php +++ b/app/Form/Scopes/ParticipantFilterScope.php @@ -22,7 +22,6 @@ class ParticipantFilterScope extends Filter * @param array $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; diff --git a/database/factories/Form/Models/ParticipantFactory.php b/database/factories/Form/Models/ParticipantFactory.php index a155d6e3..7e265003 100644 --- a/database/factories/Form/Models/ParticipantFactory.php +++ b/database/factories/Form/Models/ParticipantFactory.php @@ -27,6 +27,7 @@ class ParticipantFactory extends Factory { return [ 'data' => [], + 'parent_id' => null, ]; } diff --git a/routes/web.php b/routes/web.php index 7c8b5352..69bcb924 100644 --- a/routes/web.php +++ b/routes/web.php @@ -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'); }); diff --git a/tests/Feature/Form/ParticipantIndexActionTest.php b/tests/Feature/Form/ParticipantIndexActionTest.php index bdeac437..2a4a5559 100644 --- a/tests/Feature/Form/ParticipantIndexActionTest.php +++ b/tests/Feature/Form/ParticipantIndexActionTest.php @@ -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); + } }