feat: admin list filtering and search

This commit is contained in:
Björn Fromme committed 2026-08-06 10:57:36 +02:00
1 parent aa8fa5c1b2
commit dd658bf9d6
41 files changed
+1977 -44

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace App\Controller\Traits;
use App\Form\Model\Filter\AbstractListFilterDto;
use Symfony\Component\Form\FormView;
use Symfony\Component\HttpFoundation\Request;
/**
* Shared wiring between a list view and its filter modal — both need the same form, bound to
* the same query string.
*/
trait ListFilterTrait
{
/**
* Builds the filter form and binds it to the query string, but only when the request is
* marked as explicitly filtered. On a bare URL the passed-in defaults survive untouched,
* which is what makes "reset" simply mean "link to the route without a query string".
*
* The form writes straight into $defaults, so callers read the resolved filter from the
* object they passed in — keeping its concrete type, same as the entity edit forms — and
* get back only what they still need for rendering.
*
* @param class-string $formType
* @param array<string, mixed> $options
*/
protected function createListFilterView(
Request $request,
string $formType,
AbstractListFilterDto $defaults,
string $listRoute,
array $options = [],
): FormView {
$listUrl = $this->generateUrl($listRoute);
// The modal lives inside <body>, so swapping the body's content both refreshes the list
// and closes the modal in a single request — no OOB swap and no redirect round trip.
$form = $this->createForm($formType, $defaults, $options + [
'action' => $listUrl,
'hx_get' => $listUrl,
'hx_target' => 'body',
'hx_swap' => 'innerHTML',
'hx_push_url' => true,
]);
if ($request->query->has(AbstractListFilterDto::MARKER)) {
$form->handleRequest($request);
}
return $form->createView();
}
}