Skip to content

Feature Implementation Plan: Top Aggregated Endpoints for Varieties and Regions

📋 Todo Checklist

  • [ ] Update the VarietyRepository to add a speciesIds[] filter to the top varieties query.
  • [ ] Update the /api/varieties/top endpoint to accept the speciesIds[] filter.
  • [ ] Create a new repository method in RegionRepository to get top regions by bean count, with a countryIds[] filter.
  • [ ] Create a new /api/locations/regions/top endpoint.
  • [ ] Update OpenAPI documentation for both endpoints.
  • [ ] Write unit and integration tests for all new and updated functionality.
  • [ ] Final Review and Testing

🔍 Analysis & Investigation

Codebase Structure

  • Varieties: The logic will be updated in src/Controller/Api/VarietyController.php and src/Repository/VarietyRepository.php.
  • Regions: New logic will be added to src/Controller/Api/LocationController.php and src/Repository/RegionRepository.php.

Current Architecture

The plan builds on the previously designed architecture for "top" endpoints. It uses dedicated endpoints (/top) to return aggregated data, which is a clean and maintainable approach. The core logic for querying and aggregation is kept within the repository layer, while the controller handles API requests and responses. The addition of optional filters makes these endpoints more flexible and powerful.

Dependencies & Integration Points

  • NelmioApiDocBundle: The OpenAPI documentation for both /api/varieties/top and the new /api/locations/regions/top will be updated to reflect the new optional filter parameters (speciesIds[] and countryIds[]).
  • Doctrine: The Doctrine Query Builder will be used to add WHERE IN (...) clauses to the aggregation queries when the filters are provided.

Considerations & Challenges

  • Query Complexity: The repository methods will now have conditional logic to add the WHERE IN clause only when the filter parameters are present. This is a minor increase in complexity but is a standard pattern.
  • Performance: As before, these aggregation queries can be intensive. The filters will actually help performance by reducing the dataset before the GROUP BY operation. Caching remains a viable future optimization.

📝 Implementation Plan

Prerequisites

  • No new external dependencies are required.

Step-by-Step Implementation

  1. Update Top Varieties Endpoint

    • Files to modify: src/Controller/Api/VarietyController.php, src/Repository/VarietyRepository.php
    • VarietyController.php Changes:
      • In getTopVarieties, add logic to check for and extract the new speciesIds[] array parameter.
      • Validate the UUIDs in the array.
      • Pass the speciesIds array to the findTopByAvailableBeanCount repository method.
      • Update the #[OA\Parameter] annotations to document the new optional speciesIds[] filter.
    • VarietyRepository.php Changes:
      • Modify the findTopByAvailableBeanCount method signature to accept an optional array $speciesIds = [].
      • Inside the method, if the $speciesIds array is not empty, add the following condition to the query builder:
        $qb->andWhere('v.species IN (:speciesIds)')
           ->setParameter('speciesIds', $speciesIds);
        
  2. Create Top Regions Endpoint

    • Files to modify: src/Controller/Api/LocationController.php, src/Repository/RegionRepository.php
    • LocationController.php Changes:
      • Create a new public method getTopRegions(Request $request): JsonResponse.
      • Add the #[Route('/regions/top', name: 'regions_top', methods: ['GET'])] annotation.
      • In the method, get the limit and optional countryIds[] from the request.
      • Call a new regionRepository->findTopByAvailableBeanCount($limit, $countryIds) method.
      • Format the response to be an array of objects, each containing the region data and the beanCount.
      • Add #[OA\Get] and #[OA\Parameter] annotations to document the new endpoint and its parameters.
    • RegionRepository.php Changes:
      • Create a new public method findTopByAvailableBeanCount(int $limit = 10, array $countryIds = []): array.
      • Use the Query Builder to construct a query similar to the top varieties one.
      • If the $countryIds array is not empty, add a WHERE clause to filter the regions:
        $qb->andWhere('r.country IN (:countryIds)')
           ->setParameter('countryIds', $countryIds);
        

Testing Strategy

  • Unit Tests:
    • Update the unit test for VarietyRepository::findTopByAvailableBeanCount to test the speciesIds filter.
    • Write a new unit test for RegionRepository::findTopByAvailableBeanCount, testing both the basic aggregation and the countryIds filter.
  • Integration Tests:
    • Update the integration test for /api/varieties/top to pass the speciesIds filter and assert the results are correct.
    • Write a new integration test for /api/locations/regions/top. Test the default case, the limit parameter, and the countryIds filter.

🎯 Success Criteria

  • The /api/varieties/top endpoint can now be filtered by speciesIds[].
  • A new /api/locations/regions/top endpoint exists and returns the top regions by available bean count.
  • The /api/locations/regions/top endpoint can be filtered by countryIds[].
  • Both endpoints are documented in the OpenAPI specification.
  • All new and updated functionality is covered by tests.