From a219f0f067f7d9920f57af675096d2f6365b46cc Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 27 Oct 2025 15:57:14 +0100 Subject: [PATCH] Added dynamic filtering --- assets/controllers/user_controller.js | 24 +++++++++++++++++++++--- src/Controller/UserController.php | 26 +++++++++++++++++++++----- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/assets/controllers/user_controller.js b/assets/controllers/user_controller.js index 8163815..04f94be 100644 --- a/assets/controllers/user_controller.js +++ b/assets/controllers/user_controller.js @@ -113,6 +113,7 @@ export default class extends Controller { const first = (s) => (typeof s === "string" && s.length ? s.trim()[0].toUpperCase() : ""); const initials = `${first(data.name)}${first(data.prenom)}`; + // wrapper is for centering and circle clipping const wrapper = document.createElement("div"); wrapper.className = "avatar-wrapper"; // same size for both cases @@ -282,7 +283,7 @@ export default class extends Controller { }]; const tabulator = new Tabulator("#tabulator-userList", { langs: TABULATOR_FR_LANG, - locale: "fr", //'en' for English, 'fr' for French (en is default, no need to include it) + locale: "fr", ajaxURL: "/user/data", ajaxConfig: "GET", pagination: true, @@ -295,9 +296,26 @@ export default class extends Controller { ajaxSorting: true, ajaxFiltering: true, - rowHeight: 60, - layout: "fitColumns", // activate French + filterMode: "remote", + // Add this to send filter data + ajaxURLGenerator: function(url, config, params) { + let queryParams = new URLSearchParams(); + queryParams.append('page', params.page || 1); + queryParams.append('size', params.size || 10); + + // Add filters + if (params.filter) { + params.filter.forEach(filter => { + queryParams.append(`filter[${filter.field}]`, filter.value); + }); + } + + return `${url}?${queryParams.toString()}`; + }, + + rowHeight: 60, + layout: "fitColumns", columns }); }; diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 8f2e55b..6dfd9b1 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -393,11 +393,29 @@ class UserController extends AbstractController $page = max(1, (int)$request->query->get('page', 1)); $size = max(1, (int)$request->query->get('size', 10)); + // Get filter parameters + $filters = $request->query->all('filter', []); + $repo = $this->userRepository; - // Base query: keep your constraints intact (isDeleted=false, isActive=true) + // Base query $qb = $repo->createQueryBuilder('u') ->where('u.isDeleted = :del')->setParameter('del', false); + + // Apply filters + if (!empty($filters['name'])) { + $qb->andWhere('u.surname LIKE :name') + ->setParameter('name', '%' . $filters['name'] . '%'); + } + if (!empty($filters['prenom'])) { + $qb->andWhere('u.name LIKE :prenom') + ->setParameter('prenom', '%' . $filters['prenom'] . '%'); + } + if (!empty($filters['email'])) { + $qb->andWhere('u.email LIKE :email') + ->setParameter('email', '%' . $filters['email'] . '%'); + } + $countQb = clone $qb; $total = (int)$countQb->select('COUNT(u.id)')->getQuery()->getSingleScalarResult(); @@ -405,7 +423,7 @@ class UserController extends AbstractController $offset = ($page - 1) * $size; $rows = $qb->setFirstResult($offset)->setMaxResults($size)->getQuery()->getResult(); - // Map to array (keep isConnected) + // Map to array $data = array_map(function (User $user) { return [ 'id' => $user->getId(), @@ -419,15 +437,13 @@ class UserController extends AbstractController ]; }, $rows); - // Match organizations response shape $lastPage = (int)ceil($total / $size); return $this->json([ 'data' => $data, 'last_page' => $lastPage, - 'total' => $total, // optional but handy + 'total' => $total, ]); - } #[Route(path: '/indexTest', name: 'indexTest', methods: ['GET'])]