Skip to content

Feature Implementation Plan: Improve Shipping Country Resolution

📋 Todo Checklist

  • [ ] Create RoasterShipping entity
  • [ ] Add relationship to Roaster entity
  • [ ] Create data migration command
  • [ ] Update RoasterRepository
  • [ ] Update EntityToDtoMapper
  • [ ] Remove old properties from RoasterCrawlConfig
  • [ ] Final Review and Testing

🔍 Analysis & Investigation

Codebase Structure

The relevant files are: - src/Entity/Roaster.php: The main entity for roasters. - src/Entity/RoasterCrawlConfig.php: Currently holds the shipping information. - src/Repository/RoasterRepository.php: Contains the inefficient query that fetches roasters and their shipping information. - src/Service/Api/Mapper/EntityToDtoMapper.php: Contains the logic for resolving and mapping the shipping information.

Current Architecture

The current architecture has a tight coupling between the RoasterCrawlConfig and the shipping information for a Roaster. This leads to a complex and inefficient query in the RoasterRepository that joins multiple tables and fetches a large amount of data. The EntityToDtoMapper then has to process this data to resolve the final list of shipping countries. This is a classic N+1 problem manifesting in a single, complex query.

Dependencies & Integration Points

The main dependencies are Doctrine ORM and the Symfony Serializer component. The integration points are the API endpoints that return roaster information.

Considerations & Challenges

The main challenge will be migrating the existing data from the RoasterCrawlConfig entity to the new RoasterShipping entity without any downtime. A command-line tool will be created to handle this migration.

📝 Implementation Plan

Prerequisites

  • Ensure that the local development environment is set up and the database is running.

Step-by-Step Implementation

  1. Step 1: Create the RoasterShipping entity
  2. Files to modify: src/Entity/RoasterShipping.php (new file)
  3. Changes needed:

    • Create a new entity RoasterShipping with the following properties:
    • id (UUID)
    • roaster (ManyToOne relationship to Roaster)
    • type (string enum: 'region' or 'country_list')
    • name (string)
    • countries (ManyToMany relationship to Country)
    • exceptionCountries (ManyToMany relationship to Country)
  4. Step 2: Add the relationship to the Roaster entity

  5. Files to modify: src/Entity/Roaster.php
  6. Changes needed:

    • Add a OneToMany relationship from Roaster to RoasterShipping.
      #[ORM\OneToMany(targetEntity: RoasterShipping::class, mappedBy: 'roaster', cascade: ['persist', 'remove'])]
      private Collection $shippingInfo;
      
  7. Step 3: Create a data migration command

  8. Files to modify: src/Command/MigrateShippingDataCommand.php (new file)
  9. Changes needed:

    • Create a new Symfony command that:
    • Fetches all RoasterCrawlConfig entities.
    • For each crawlConfig, creates a new RoasterShipping entity.
    • Copies the shippingRegion, shipsTo, and exceptionCountries data to the new RoasterShipping entity.
    • Persists the new RoasterShipping entities to the database.
  10. Step 4: Update RoasterRepository

  11. Files to modify: src/Repository/RoasterRepository.php
  12. Changes needed:

    • Simplify the executeRoasterQuery and findDtoById methods to remove the joins related to RoasterCrawlConfig.
    • Instead, join the new RoasterShipping entity. ```php $qb = $this->createQueryBuilder('r') ->leftJoin('r.country', 'c') ->leftJoin('r.shippingInfo', 'rs') -

      leftJoin('rs.countries', 'rsc') ->leftJoin('rs.exceptionCountries', 'rsec') ->addSelect('c', 'rs', 'rsc', 'rsec') ->orderBy('r.name', 'ASC'); ```

  13. Step 5: Update EntityToDtoMapper

  14. Files to modify: src/Service/Api/Mapper/EntityToDtoMapper.php
  15. Changes needed:

    • Update the mapRoasterShippingToDto method to use the new RoasterShipping entity.
    • The logic will be similar, but it will iterate over the shippingInfo collection of the Roaster entity instead of the crawlConfigs.
  16. Step 6: Remove old properties from RoasterCrawlConfig

  17. Files to modify: src/Entity/RoasterCrawlConfig.php
  18. Changes needed:
    • After the data migration is complete and the code is updated, remove the shipsTo, shippingRegion, and exceptionCountries properties from the RoasterCrawlConfig entity.
    • Create a new database migration to remove the corresponding columns and tables.

Testing Strategy

  • Run the existing test suite to ensure that no functionality is broken.
  • Create a new integration test that verifies that the roaster API endpoint returns the correct shipping information.
  • Manually test the API endpoint to confirm that the performance has improved.

🎯 Success Criteria

  • The API endpoints that return roaster information are significantly faster and no longer time out.
  • The shipping information for roasters is correctly resolved and returned by the API.
  • The codebase is simplified and easier to maintain.