Add participants parent and child in request filter
This commit is contained in:
parent
a0842afd47
commit
78d6c6d864
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Form\Actions;
|
||||
|
||||
use App\Form\FilterScope;
|
||||
use App\Form\Scopes\FormFilterScope;
|
||||
use App\Form\Models\Form;
|
||||
use App\Form\Resources\FormApiResource;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
|
@ -20,7 +20,7 @@ class FormApiListAction
|
|||
*/
|
||||
public function handle(string $filter, int $perPage): LengthAwarePaginator
|
||||
{
|
||||
return FilterScope::fromRequest($filter)->getQuery()->paginate($perPage);
|
||||
return FormFilterScope::fromRequest($filter)->getQuery()->paginate($perPage);
|
||||
}
|
||||
|
||||
public function asController(ActionRequest $request): AnonymousResourceCollection
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Form\Actions;
|
||||
|
||||
use App\Form\FilterScope;
|
||||
use App\Form\Scopes\FormFilterScope;
|
||||
use App\Form\Models\Form;
|
||||
use App\Form\Resources\FormResource;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
|
@ -20,7 +20,7 @@ class FormIndexAction
|
|||
*/
|
||||
public function handle(string $filter): LengthAwarePaginator
|
||||
{
|
||||
return FilterScope::fromRequest($filter)->getQuery()->query(fn ($query) => $query->withCount('participants'))->paginate(15);
|
||||
return FormFilterScope::fromRequest($filter)->getQuery()->query(fn ($query) => $query->withCount('participants'))->paginate(15);
|
||||
}
|
||||
|
||||
public function asController(ActionRequest $request): Response
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Form\Actions;
|
|||
use App\Form\Models\Form;
|
||||
use App\Form\Models\Participant;
|
||||
use App\Form\Resources\ParticipantResource;
|
||||
use App\Form\Scopes\ParticipantFilterScope;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
@ -16,14 +17,15 @@ class ParticipantIndexAction
|
|||
/**
|
||||
* @return LengthAwarePaginator<Participant>
|
||||
*/
|
||||
public function handle(Form $form): LengthAwarePaginator
|
||||
public function handle(Form $form, ParticipantFilterScope $filter): LengthAwarePaginator
|
||||
{
|
||||
return $form->participants()->with('form')->paginate(15);
|
||||
return $form->participants()->withFilter($filter)->with('form')->paginate(15);
|
||||
}
|
||||
|
||||
public function asController(Form $form): AnonymousResourceCollection
|
||||
{
|
||||
return ParticipantResource::collection($this->handle($form))
|
||||
$filter = ParticipantFilterScope::fromRequest(request()->input('filter'));
|
||||
return ParticipantResource::collection($this->handle($form, $filter))
|
||||
->additional(['meta' => ParticipantResource::meta($form)]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
namespace App\Form\Models;
|
||||
|
||||
use App\Form\Scopes\ParticipantFilterScope;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Participant extends Model
|
||||
{
|
||||
|
@ -23,4 +26,21 @@ class Participant extends Model
|
|||
{
|
||||
return $this->belongsTo(Form::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HasMany<self>
|
||||
*/
|
||||
public function children(): HasMany
|
||||
{
|
||||
return $this->hasMany(self::class, 'parent_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Builder<self> $query
|
||||
* @return Builder<self>
|
||||
*/
|
||||
public function scopeWithFilter(Builder $query, ParticipantFilterScope $filter): Builder
|
||||
{
|
||||
return $filter->apply($query);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace App\Form\Resources;
|
|||
|
||||
use App\Form\Enums\NamiType;
|
||||
use App\Form\Fields\Field;
|
||||
use App\Form\FilterScope;
|
||||
use App\Form\Scopes\FormFilterScope;
|
||||
use App\Form\Models\Form;
|
||||
use App\Form\Models\Formtemplate;
|
||||
use App\Group;
|
||||
|
@ -59,7 +59,7 @@ class FormResource extends JsonResource
|
|||
'base_url' => url(''),
|
||||
'groups' => Group::forSelect(),
|
||||
'fields' => Field::asMeta(),
|
||||
'filter' => FilterScope::fromRequest(request()->input('filter', '')),
|
||||
'filter' => FormFilterScope::fromRequest(request()->input('filter', '')),
|
||||
'links' => [
|
||||
'store' => route('form.store'),
|
||||
'formtemplate_index' => route('formtemplate.index'),
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
namespace App\Form\Scopes;
|
||||
|
||||
use Laravel\Scout\Builder;
|
||||
use App\Form\Models\Form;
|
||||
use App\Lib\Filter;
|
||||
use App\Lib\ScoutFilter;
|
||||
use Spatie\LaravelData\Attributes\MapInputName;
|
||||
use Spatie\LaravelData\Attributes\MapOutputName;
|
||||
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
|
||||
|
||||
/**
|
||||
* @extends Filter<Form>
|
||||
* @extends ScoutFilter<Form>
|
||||
*/
|
||||
#[MapInputName(SnakeCaseMapper::class)]
|
||||
#[MapOutputName(SnakeCaseMapper::class)]
|
||||
class FilterScope extends Filter
|
||||
class FormFilterScope extends ScoutFilter
|
||||
{
|
||||
public function __construct(
|
||||
public ?string $search = '',
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form\Scopes;
|
||||
|
||||
use App\Form\Models\Participant;
|
||||
use App\Lib\Filter;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Spatie\LaravelData\Attributes\MapInputName;
|
||||
use Spatie\LaravelData\Attributes\MapOutputName;
|
||||
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
|
||||
|
||||
/**
|
||||
* @extends Filter<Participant>
|
||||
*/
|
||||
#[MapInputName(SnakeCaseMapper::class)]
|
||||
#[MapOutputName(SnakeCaseMapper::class)]
|
||||
class ParticipantFilterScope extends Filter
|
||||
{
|
||||
public function __construct(
|
||||
public ?int $parent = null,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace App\Lib;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Laravel\Scout\Builder;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
/**
|
||||
|
@ -14,10 +14,10 @@ abstract class Filter extends Data
|
|||
{
|
||||
|
||||
/**
|
||||
* @return Builder
|
||||
* @param Builder<T> $query
|
||||
* @return Builder<T>
|
||||
*/
|
||||
abstract public function getQuery(): Builder;
|
||||
protected Builder $query;
|
||||
abstract public function apply(Builder $query): Builder;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|string|null $request
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Laravel\Scout\Builder;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
/**
|
||||
* @template T of Model
|
||||
* @property Builder $query
|
||||
*/
|
||||
abstract class ScoutFilter extends Data
|
||||
{
|
||||
|
||||
/**
|
||||
* @return Builder
|
||||
*/
|
||||
abstract public function getQuery(): Builder;
|
||||
protected Builder $query;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|string|null $request
|
||||
*/
|
||||
public static function fromRequest(array|string|null $request = null): static
|
||||
{
|
||||
$payload = is_string($request)
|
||||
? json_decode(rawurldecode(base64_decode($request)), true)
|
||||
: $request;
|
||||
|
||||
return static::fromPost($payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $post
|
||||
*/
|
||||
public static function fromPost(?array $post = null): static
|
||||
{
|
||||
return static::withoutMagicalCreationFrom($post ?: []);
|
||||
}
|
||||
}
|
|
@ -5,8 +5,8 @@ namespace App\Member;
|
|||
use App\Activity;
|
||||
use App\Group;
|
||||
use App\Invoice\BillKind;
|
||||
use App\Lib\Filter;
|
||||
use App\Subactivity;
|
||||
use App\Lib\ScoutFilter;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Scout\Builder;
|
||||
use Spatie\LaravelData\Attributes\MapInputName;
|
||||
|
@ -14,11 +14,11 @@ use Spatie\LaravelData\Attributes\MapOutputName;
|
|||
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
|
||||
|
||||
/**
|
||||
* @extends Filter<Member>
|
||||
* @extends ScoutFilter<Member>
|
||||
*/
|
||||
#[MapInputName(SnakeCaseMapper::class)]
|
||||
#[MapOutputName(SnakeCaseMapper::class)]
|
||||
class FilterScope extends Filter
|
||||
class FilterScope extends ScoutFilter
|
||||
{
|
||||
/**
|
||||
* @param array<int, int> $activityIds
|
||||
|
|
|
@ -17,7 +17,7 @@ return new class extends Migration
|
|||
$table->id();
|
||||
$table->json('data');
|
||||
$table->foreignId('form_id');
|
||||
$table->foreignId('parent_id', 'participants')->nullable();
|
||||
$table->foreignId('parent_id')->nullable();
|
||||
$table->string('mitgliedsnr')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
|
|
@ -54,6 +54,30 @@ class ParticipantIndexActionTest extends FormTestCase
|
|||
->assertJsonPath('meta.form_meta.sorting', ['vorname', 'asc']);
|
||||
}
|
||||
|
||||
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();
|
||||
|
|
Loading…
Reference in New Issue