Skip to content

Feature Implementation Plan: Hierarchical Location Filter (Updated)

📋 Todo Checklist

  • [ ] Create a new LocationController to house all location-related endpoints.
  • [ ] Move the existing /api/countries endpoint to /api/locations/countries.
  • [ ] Move the existing /api/regions endpoint to /api/locations/regions.
  • [ ] Add pagination and countryId filtering to the /api/locations/regions endpoint.
  • [ ] Implement the new /api/locations/countries-by-continent endpoint.
  • [ ] Update CoffeeBeanController to use the new locationIds filter metadata.
  • [ ] Update CoffeeBeanRepository to filter by continent and country from locationIds.
  • [ ] Write unit and integration tests for all changes.
  • [ ] Final Review and Testing

🔍 Analysis & Investigation

Codebase Structure

  • Controllers: API logic is in src/Controller/Api/. CountryController.php and RegionController.php will be refactored into a new LocationController.php.
  • Repositories: CountryRepository.php and RegionRepository.php contain the data access logic. CoffeeBeanRepository.php handles the core filtering for beans.
  • Entities: Country.php and Region.php are the key entities. The Country entity already contains continentCode and continentName.

Current Architecture

The application uses a standard Symfony setup. The plan is to consolidate location-related endpoints into a single LocationController to improve organization. The new endpoints will follow existing patterns of using repositories for data and OpenAPI annotations for documentation.

Dependencies & Integration Points

  • NelmioApiDocBundle: Will be used to document the new and moved endpoints.
  • Doctrine: The Doctrine Query Builder will be used to implement the new repository methods and filtering logic.
  • Symfony Paginator: Will be used to add pagination to the regions endpoint.

Considerations & Challenges

  • Route Refactoring: Moving existing endpoints requires careful management of routes to avoid breaking the frontend. Redirects or clear communication with the frontend team will be necessary.
  • Repository Logic: The query to fetch countries with coffee beans needs to be efficient. It will involve joins across three tables (Country, Region, CoffeeBean) and a condition to ensure beans exist.
  • Pagination: Adding pagination to the /api/locations/regions endpoint is a new requirement for that endpoint and must be implemented correctly.

📝 Implementation Plan

Prerequisites

  • No new external dependencies are required.

Step-by-Step Implementation

  1. Create LocationController and Refactor Routes

    • Files to create: src/Controller/Api/LocationController.php
    • Files to modify: config/routes.php (or relevant route configuration)
    • Files to delete: src/Controller/Api/CountryController.php, src/Controller/Api/RegionController.php
    • Changes needed:
      • Create a new LocationController.
      • Move the logic from CountryController and RegionController into LocationController.
      • Update the #[Route] annotations to reflect the new paths: /api/locations/countries and /api/locations/regions.
      • Remove the old controller files.
  2. Update the Regions Endpoint

    • Files to modify: src/Controller/Api/LocationController.php, src/Repository/RegionRepository.php
    • Changes needed:
      • In LocationController, update the getRegions method to handle pagination parameters (page, limit).
      • In RegionRepository, modify the findByFilters method to use Doctrine's Paginator to return a paginated result set.
      • The countryId filter is already implemented, so no changes are needed there, but ensure it works with pagination.
  3. Implement countries-by-continent Endpoint

    • Files to modify: src/Controller/Api/LocationController.php, src/Repository/CountryRepository.php
    • Changes needed:
      • In CountryRepository, create a new method findCountriesWithCoffeeBeans(). This method will:
        • Join Country with Region (c.regions).
        • Join Region with CoffeeBean (r.coffeeBeans).
        • Use GROUP BY c.id and HAVING COUNT(cb.id) > 0 to ensure only countries with at least one coffee bean are returned.
        • The method should return an array of Country entities.
      • In LocationController, add a new method getCountriesByContinent with the route /api/locations/countries-by-continent.
      • This method will call countryRepository->findCountriesWithCoffeeBeans().
      • It will then process the result to build the hierarchical structure, grouping countries by continentCode.
  4. Update Coffee Bean Filtering

    • Files to modify: src/Controller/Api/CoffeeBeanController.php, src/Repository/CoffeeBeanRepository.php
    • Changes needed:
      • In CoffeeBeanController, update the #[OA\Parameter] for locationIds[] to change the label and endpoint as specified.
      • In CoffeeBeanRepository, update the createBaseFilterQueryBuilder method. The logic for locationIds should now only handle continent codes and country IDs. It should create an OR condition for c.continentCode IN (:continentCodes) and c.id IN (:countryIds).

Testing Strategy

  • Unit Tests:
    • Write a unit test for the new CountryRepository::findCountriesWithCoffeeBeans() method.
    • Write a unit test for the LocationController to verify the response of the getCountriesByContinent endpoint.
    • Update tests for the moved country and region endpoints to reflect pagination and new routes.
  • Integration Tests:
    • Write an integration test for /api/locations/countries-by-continent.
    • Update integration tests for /api/countries and /api/regions to point to the new /api/locations/* routes.
    • Update the integration test for /api/coffee-beans to use the updated locationIds filter and verify the results.

🎯 Success Criteria

  • The /api/countries and /api/regions endpoints are successfully moved to /api/locations/countries and /api/locations/regions.
  • The /api/locations/regions endpoint is paginated.
  • The /api/locations/countries-by-continent endpoint returns the correct hierarchical data, filtered as required.
  • The locationIds filter on /api/coffee-beans works with continent codes and country IDs.
  • The frontend is able to consume the new and updated endpoints.
  • All changes are covered by tests and there are no regressions.