adrema/app/Member/FilterScope.php

131 lines
4.3 KiB
PHP
Raw Normal View History

2023-03-14 23:27:15 +01:00
<?php
namespace App\Member;
2023-04-18 22:08:45 +02:00
use App\Invoice\BillKind;
2023-03-14 23:27:15 +01:00
use App\Lib\Filter;
2024-01-28 11:42:32 +01:00
use Illuminate\Support\Collection;
use Laravel\Scout\Builder;
2023-03-14 23:27:15 +01:00
use Spatie\LaravelData\Attributes\MapInputName;
use Spatie\LaravelData\Attributes\MapOutputName;
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
/**
* @extends Filter<Member>
*/
#[MapInputName(SnakeCaseMapper::class)]
#[MapOutputName(SnakeCaseMapper::class)]
class FilterScope extends Filter
{
2023-06-14 17:11:42 +02:00
/**
* @param array<int, int> $activityIds
* @param array<int, int> $subactivityIds
2023-06-14 17:29:22 +02:00
* @param array<int, int> $groupIds
2023-07-10 11:36:58 +02:00
* @param array<int, int> $include
* @param array<int, int> $exclude
2023-06-14 17:11:42 +02:00
*/
2023-03-14 23:27:15 +01:00
public function __construct(
public bool $ausstand = false,
public ?string $billKind = null,
2023-06-14 16:20:18 +02:00
public array $activityIds = [],
public array $subactivityIds = [],
public ?string $search = '',
2023-06-14 17:29:22 +02:00
public array $groupIds = [],
2023-07-10 11:36:58 +02:00
public array $include = [],
public array $exclude = [],
2023-07-24 16:55:07 +02:00
public ?bool $hasFullAddress = null,
public ?bool $hasBirthday = null,
2023-03-14 23:27:15 +01:00
) {
}
2024-01-28 11:42:32 +01:00
public function getQuery(): Builder
{
$this->search = $this->search ?: '';
return Member::search($this->search, function ($engine, string $query, array $options) {
$filter = collect([]);
if ($this->hasFullAddress === true) {
$filter->push('address IS NOT EMPTY');
}
if ($this->hasFullAddress === false) {
$filter->push('address IS EMPTY');
}
if ($this->hasBirthday === false) {
$filter->push('birthday IS NULL');
}
if ($this->hasBirthday === true) {
$filter->push('birthday IS NOT NULL');
}
if ($this->ausstand === true) {
$filter->push('ausstand > 0');
}
if ($this->billKind) {
$filter->push('bill_kind = ' . BillKind::fromValue($this->billKind)->value);
}
if (count($this->groupIds)) {
$filter->push($this->inExpression('group_id', $this->groupIds));
}
if (!$this->subactivityIds && $this->activityIds) {
$filter->push($this->inExpression('memberships.activity_id', $this->activityIds));
}
if ($this->subactivityIds && !$this->activityIds) {
$filter->push($this->inExpression('memberships.subactivity_id', $this->subactivityIds));
}
if ($this->subactivityIds && $this->activityIds) {
$combinations = collect($this->activityIds)
->map(fn ($activityId) => collect($this->subactivityIds)->map(fn ($subactivityId) => $activityId . '|' . $subactivityId))
->flatten()
->map(fn ($combination) => str($combination)->wrap('"'));
$filter->push($this->inExpression('memberships.both', $combinations));
}
if (count($this->exclude)) {
$filter->push($this->notInExpression('id', $this->exclude));
}
$andFilter = $filter->map(fn ($expression) => "($expression)")->implode(' AND ');
$options['filter'] = $this->implode(collect([$andFilter])->push($this->inExpression('id', $this->include)), 'OR');
$options['sort'] = ['lastname:asc', 'firstname:asc'];
return $engine->search($query, $options);
});
}
2023-03-14 23:27:15 +01:00
/**
2024-01-28 11:42:32 +01:00
* @param Collection<int, mixed> $values
2023-03-14 23:27:15 +01:00
*/
2024-01-28 11:42:32 +01:00
protected function implode(Collection $values, string $between): string
2023-03-14 23:27:15 +01:00
{
2024-01-28 11:42:32 +01:00
return $values->filter(fn ($expression) => $expression)->implode(" {$between} ");
2023-03-14 23:27:15 +01:00
}
/**
2024-01-28 11:42:32 +01:00
* @param array<int, mixed>|Collection<int, mixed> $values
2023-03-14 23:27:15 +01:00
*/
2024-01-28 11:42:32 +01:00
private function inExpression(string $key, array|Collection $values): ?string
2023-03-14 23:27:15 +01:00
{
2024-01-28 11:42:32 +01:00
if (!count($values)) {
return null;
}
$valueString = Collection::wrap($values)->implode(',');
return "$key IN [{$valueString}]";
}
/**
* @param array<int, mixed>|Collection<int, mixed> $values
*/
private function notInExpression(string $key, array|Collection $values): ?string
{
if (!count($values)) {
return null;
}
$valueString = Collection::wrap($values)->implode(',');
return "$key NOT IN [{$valueString}]";
2023-03-14 23:27:15 +01:00
}
}