From 38e99e786d952fda148baff3af45d7a1af7b70e3 Mon Sep 17 00:00:00 2001
From: Julian PEREZ-RAMIREZ <julian.perez-ramirez@imt-atlantique.net>
Date: Sat, 15 Mar 2025 15:09:51 +0100
Subject: [PATCH] adding filter and pagination to get items endpoint

---
 .../web_app/src/Controller/ItemController.php | 57 ++++++++++++++-----
 .../web_app/src/Repository/ItemRepository.php | 27 +++++++++
 2 files changed, 71 insertions(+), 13 deletions(-)

diff --git a/server/web_app/src/Controller/ItemController.php b/server/web_app/src/Controller/ItemController.php
index b200cec..cb5feb7 100644
--- a/server/web_app/src/Controller/ItemController.php
+++ b/server/web_app/src/Controller/ItemController.php
@@ -33,30 +33,61 @@ final class ItemController extends AbstractController
     }
 
     #[Route('', methods: ['GET'])]
-    public function getAllItems(): JsonResponse
+    public function getAllItems(Request $req): JsonResponse
     {
-        $items = $this->itemRepository->findAllItems();
+        // Validate "onlyBought" as boolean (default: false)
+        $onlyBought = filter_var($req->query->get('onlyBought', false), 
+            FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? false;
+
+        // Validate "sortBy" to allow only 'createdAt' or 'price'
+        $allowedSortBy = ['createdAt', 'price'];
+        $sortBy = $req->query->get('sortBy', 'createdAt');
+        if (!in_array($sortBy, $allowedSortBy, true)) {
+            $sortBy = 'price';
+        }
+
+        // Validate "sort" to allow only 'asc' or 'desc'
+        $allowedSort = ['asc', 'desc'];
+        $sort = strtolower($req->query->get('sort', 'asc'));
+        if (!in_array($sort, $allowedSort, true)) {
+            $sort = 'desc';
+        }
+
+        // Validate "max" as a positive integer (default: 10)
+        $max = filter_var($req->query->get('max', 10), FILTER_VALIDATE_INT,
+            ["options" => ["min_range" => 1]]) ?: 10;
+
+        // Validate "page" as a positive integer (default: 1)
+        $page = filter_var($req->query->get('page', 1), FILTER_VALIDATE_INT,
+            ["options" => ["min_range" => 1]]) ?: 1;
+
+        // Fetch items from repository with filters
+        $items = $this->itemRepository->findAllItemsFiltered($onlyBought, $sortBy,
+             $sort, $max, $page);
 
         if (!$items) {
-            return new JsonResponse(['error' => 'Item not found'], Response::HTTP_NOT_FOUND);
+            return new JsonResponse(['error' => 'No items found'], Response::HTTP_NOT_FOUND);
         }
 
-        $itemArray = array_map(fn($item) => 
-        [
+        $itemArray = array_map(fn($item) => [
             'id' => $item->getId(),
             'wishList' => $item->getWishList(),
             'title' => $item->getTitle(),
-            'description' =>$item->getDescription(),
-            'price' =>$item->getPrice(),
-            'purchaseUrl' =>$item->getPurchaseUrl(),
-            'createdAt' => $item->getCreatedAt()    
-        ]
-        , $items);
-        
+            'description' => $item->getDescription(),
+            'price' => $item->getPrice(),
+            'purchaseUrl' => $item->getPurchaseUrl(),
+            'createdAt' => $item->getCreatedAt()
+        ], $items);
+
         return $this->json([
             'items' => $itemArray,
-            'path' => 'src/Controller/ItemController.php',
+            'page' => $page,
+            'max' => $max,
+            'sortBy' => $sortBy,
+            'sort' => $sort,
+            'onlyBought' => $onlyBought
         ]);
+
     }
 
     #[Route('/{itemId}', methods: ['GET'])]
diff --git a/server/web_app/src/Repository/ItemRepository.php b/server/web_app/src/Repository/ItemRepository.php
index 48e7dca..abc603f 100644
--- a/server/web_app/src/Repository/ItemRepository.php
+++ b/server/web_app/src/Repository/ItemRepository.php
@@ -25,4 +25,31 @@ class ItemRepository extends ServiceEntityRepository
     {
         return $this->findOneBy(['id' => $id]);
     }
+
+    // Custom method to manage pagination and filters.
+    public function findAllItemsFiltered(bool $onlyBought, string $sortBy, string $sort, int $max, int $page)
+    {
+        $queryBuilder = $this->createQueryBuilder('i');
+
+        if ($onlyBought) {
+            $queryBuilder->innerJoin('App\Entity\Purchase', 'p', 'WITH', 'p.item = i.id');
+        }
+
+        // This ensures sortBy is either 'createdAt' or 'price'
+        if (!in_array($sortBy, ['createdAt', 'price'])) {
+            $sortBy = 'price'; // Default to sorting by price
+        }
+
+        // Ensure sort order is either 'asc' or 'desc'
+        if (!in_array(strtolower($sort), ['asc', 'desc'])) {
+            $sort = 'desc'; // Default to sorting by desc
+        }
+
+        $queryBuilder->orderBy("i.$sortBy", $sort)
+                    ->setMaxResults($max)
+                    ->setFirstResult(($page - 1) * $max);
+
+        return $queryBuilder->getQuery()->getResult();
+    }
+
 }
-- 
GitLab