Skip to content

Architecture Backend (Symfony 7.3)

Le backend est conçu comme une API REST stateless, isolant strictement la logique métier des entités de persistance. Chaque couche a une responsabilité unique et non-ambiguë.


🔄 Flux de Données

Le chemin d'une requête HTTP à travers les couches applicatives :

graph LR
    A["🌐 HTTP Request"] --> B["Controller"]
    B --> C["RequestMapper"]
    C --> D["RequestDTO"]
    D --> E["Manager"]
    E --> F["Service\n(logique métier)"]
    E --> G["Repository"]
    G --> H[("PostgreSQL")]
    E --> I["Mapper"]
    I --> J["ResponseDTO"]
    J --> K["✅ ApiResponse JSON"]

📐 Responsabilité de chaque couche

Couche Rôle Exemple
Controller Point d'entrée HTTP. Délègue immédiatement, ne contient aucune logique métier. ProductController::list()
RequestMapper Extrait, valide et transforme les paramètres bruts en RequestDTO typé. ProductRequestMapper
Manager Orchestre les Services et les Repositories. Porte la logique de persistance. ProductManager::list()
Service Logique métier pure, sans dépendance à Doctrine. ShipmentCalculatorService
Mapper Conversion bidirectionnelle Entity ↔ DTO. Isole la couche de présentation. ProductMapper::toResponse()
Repository Accès aux données. Construit les requêtes via le QueryBuilder Doctrine. ProductRepository::findFiltered()

🛠️ Exemple : RequestMapper

Un RequestMapper centralise tout le traitement des entrées, déchargeant le contrôleur de cette responsabilité :

public function list(Request $request): JsonResponse
{
    $page   = max(1, (int) $request->query->get('page', 1));
    $search = trim($request->query->get('search', ''));
    // Validation manuelle, logique éparpillée dans le controller...
}
public function list(Request $request): JsonResponse
{
    $dto = $this->requestMapper->mapProductListRequest($request);
    return $this->apiResponse->success($this->manager->list($dto));
}

Le RequestMapper s'occupe de l'extraction, de la validation via le composant Symfony\Validator, et de l'injection dans un DTO typé. Si les données sont invalides, une ValidationException est levée avant même d'atteindre le Manager.


🧪 Stratégie de Tests

L'architecture est pensée pour être testable par couche :

  • Tests Unitaires : Chaque couche (Mapper, Service, Manager) est testée de manière isolée grâce à la séparation stricte des responsabilités. Les dépendances sont mockées via PHPUnit.
  • Tests Fonctionnels : Les Controllers sont testés de bout en bout via le KernelBrowser de Symfony, validant les statuts HTTP, la structure JSON et les règles de sécurité.
  • NelmioApiDoc : La documentation OpenAPI est générée automatiquement à partir des annotations du code, garantissant une cohérence permanente entre le code et le contrat d'interface.

Avantage clé : Grâce à l'isolation des couches, il est possible de tester le ShipmentCalculatorService sans base de données, ni contexte HTTP — ce qui rend les tests rapides et fiables.