Skip to content

Feature Implementation Plan: Save Product Images

📋 Todo Checklist

  • [ ] Install league/flysystem-bundle and a storage adapter (e.g., league/flysystem-aws-s3-v3).
  • [ ] Configure the Flysystem bundle for configurable storage (local and S3).
  • [ ] Create a new Image entity and repository.
  • [ ] Update the CoffeeBean entity to have a one-to-many relationship with the Image entity.
  • [ ] Create a new ImageController to handle image uploads and adding images by URL.
  • [ ] Implement a background job (Symfony Messenger) for processing images added by URL.
  • [ ] Update CoffeeBeanCrudController to manage the new image relationship.
  • [ ] Update the API serialization to include the array of images.
  • [ ] Write unit and integration tests for the new functionality.
  • [ ] Final Review and Testing

🔍 Analysis & Investigation

Codebase Structure

  • Entities: A new Image entity is required. The CoffeeBean entity will be modified to replace the imageUrl field with a collection of Image entities.
  • Admin: The admin panel is built with easycorp/easyadmin-bundle. The configuration is in src/Controller/Admin/DashboardController.php, and there is a corresponding CoffeeBeanCrudController.php that will need to be updated.
  • Dependencies: The project is missing a filesystem abstraction layer. league/flysystem-bundle will be added to handle this.

Current Architecture

The application uses a standard Symfony architecture. The plan is to introduce a new Image entity and manage it through a dedicated controller and an updated admin interface. For adding images via URL, a message-based approach with Symfony Messenger will be used to avoid blocking API requests and to handle potential download failures gracefully.

Dependencies & Integration Points

  • league/flysystem-bundle: This will be a new dependency to abstract the filesystem. It will be configured to allow switching between local storage and S3-compatible services via environment variables.
  • EasyAdminBundle: The CoffeeBeanCrudController will be updated to use EasyAdmin's CollectionField and a custom form type to manage the images, providing a user-friendly grid layout in the admin panel.
  • Symfony Messenger: Will be used to process image downloads from URLs in the background.

Considerations & Challenges

  • Database Migration: The change from a simple imageUrl string to a one-to-many relationship requires a carefully written database migration to preserve existing image URLs.
  • File Uploads vs. URL Processing: The system needs to handle both direct file uploads and asynchronous URL fetching. The implementation must be robust to handle both cases.
  • Configuration: The storage solution needs to be easily configurable for different environments (development, staging, production). This will be handled through Symfony's environment variable system.
  • Admin UI: The admin interface for managing images should be intuitive. A grid layout with previews and options to add/remove images is desired.

📝 Implementation Plan

Prerequisites

  • Add league/flysystem-bundle and the required adapters to composer.json.
    composer require league/flysystem-bundle league/flysystem-aws-s3-v3 league/flysystem-local
    

Step-by-Step Implementation

  1. Configure Flysystem

    • Files to create: config/packages/flysystem.yaml
    • Changes needed:
      • Configure two storage adapters: one for local storage (default.storage) and one for S3 (aws.storage).
      • Use an environment variable (STORAGE_ADAPTER) to determine which storage to use as the default.
  2. Create the Image Entity

    • Files to create: src/Entity/Image.php, src/Repository/ImageRepository.php
    • Changes needed:
      • Create an Image entity with fields: id (UUID), coffeeBean (ManyToOne), path (string), originalUrl (string, nullable), createdAt.
      • Generate the corresponding repository.
  3. Update CoffeeBean Entity and Create Migration

    • Files to modify: src/Entity/CoffeeBean.php
    • Changes needed:
      • Remove the imageUrl property.
      • Add a new images property with a OneToMany relationship to the Image entity.
      • Add the #[Groups(['coffee:read'])] annotation to the images collection.
      • Generate a database migration. Manually edit the migration to move the data from the old imageUrl column to the new images table for existing records.
  4. Implement Image Upload and URL Processing

    • Files to create: src/Controller/Api/ImageController.php, src/Message/ProcessImageUrlMessage.php, src/MessageHandler/ProcessImageUrlMessageHandler.php, src/Form/ImageType.php
    • Changes needed:
      • Create an ImageController with two endpoints:
        • POST /api/images/upload: Handles direct file uploads, saves the file to the configured storage, and creates an Image entity.
        • POST /api/images/add-by-url: Takes a URL, dispatches a ProcessImageUrlMessage to the messenger bus, and returns an initial response.
      • Create the ProcessImageUrlMessageHandler to consume the message, download the image, save it to storage, and update the Image entity.
  5. Update Admin Interface

    • Files to modify: src/Controller/Admin/CoffeeBeanCrudController.php
    • Changes needed:
      • In CoffeeBeanCrudController, replace the TextField for imageUrl with a CollectionField for the images collection.
      • Use setEntryType(ImageType::class) for the CollectionField to provide a custom form for each image.
      • The ImageType form will include fields for file upload and to display the image preview.
      • This will result in the desired grid layout for managing images.

Testing Strategy

  • Unit Tests:
    • Write a unit test for the ProcessImageUrlMessageHandler to ensure it correctly processes image URLs.
    • Write unit tests for the Image entity and its relationship with CoffeeBean.
  • Integration Tests:
    • Write integration tests for the new endpoints in ImageController.
    • Update the integration tests for the /api/coffee-beans endpoint to verify that the images array is present and contains the correct data.
    • Test the admin interface manually to ensure the image management UI works as expected.

🎯 Success Criteria

  • Images can be uploaded and associated with a coffee bean via the admin panel and the API.
  • Images can be added by providing a URL, and they are processed in the background.
  • The storage location is configurable via an environment variable.
  • The /api/coffee-beans endpoint returns an array of image URLs for each bean.
  • The admin panel displays a grid of images for each coffee bean, with options to add and remove them.
  • All new functionality is covered by tests.