Pourquoi adopter l’architecture hexagonale en PHP/Symfony pour vos applications métiers
L’architecture hexagonale permet de résoudre les problèmes des applications Symfony classiques : contrôleurs trop lourds, services qui mélangent métier et technique, logique noyée dans l’infrastructure et refactoring compliqué. En remettant le domaine au centre, en utilisant des ports pour définir les besoins métier et des adaptateurs pour gérer le framework, les bases de données ou les APIs, on obtient une application plus testable, plus stable et beaucoup plus durable. C’est une approche moderne qui facilite l’évolution, réduit les dépendances au framework et s’intègre naturellement avec DDD et la Clean Architecture - idéale pour les projets métiers sérieux et long terme.
Quand on travaille depuis des années en PHP/Symfony, on finit tous par croiser les mêmes douleurs : des contrôleurs qui grossissent, des services “fourre-tout”, des règles métiers noyées dans le technique… et chaque refacto devient une opération à cœur ouvert.
L’architecture hexagonale (Ports & Adapters) apporte une réponse très concrète : structurer l’application pour qu’elle reste compréhensible, testable et durable, même après plusieurs années et plusieurs équipes.
Dans cet article, je te partage une vision pragmatique de l’hexagonal appliqué à PHP et Symfony, telle qu’on peut la mettre en place dans des projets métiers réels.
- contrôleurs qui grossissent à vue d’œil ;
- services qui appellent directement le framework, la base, l’API externe, le bus de messages ;
- règles métiers noyées dans le code technique ;
- refacto risquée, lente, coûteuse.
1. Le problème des architectures “classiques” en Symfony
Le schéma classique dans beaucoup de projets Symfony ressemble à ça :
- des controllers qui portent une grosse partie du métier ;
- des services qui mélangent logique métier, accès DB, appels API, envoi d’e-mails ;
- des entités Doctrine utilisées partout (parfois même comme DTO côté API).
Au début, ça va vite. Mais très vite aussi :
- chaque changement implique de toucher à 5–6 endroits ;
- les tests unitaires deviennent pénibles sans démarrer tout Symfony ;
- on dépend fortement d’un framework, d’un ORM, d’une base, d’un provider externe.
Résultat : l’application vieillit mal, le coût du changement explose, et chaque montée de version (PHP, Symfony, MySQL/PostgreSQL, etc.) devient un mini-projet.
2. Les principes clés de l’architecture hexagonale
L’architecture hexagonale repose sur quelques idées simples, mais très puissantes.
2.1. Le domaine au centre
Au cœur de l’application, on place le métier :
- des entités métier (pas forcément des entités Doctrine) ;
- des services métier (domain services) ;
- des règles fonctionnelles.
Ce code ne doit dépendre ni de Symfony, ni de Doctrine, ni d’aucune lib externe. C’est le cœur de valeur de ton application : il doit rester le plus “pur” possible.
2.2. Les ports
Les ports sont des interfaces qui décrivent ce dont le domaine a besoin :
-
LeadRepositoryInterfacepour persister un lead ; -
NotifierInterfacepour envoyer une notification ; -
PaymentGatewayInterfacepour déclencher un paiement.
Le domaine parle uniquement à des interfaces, jamais à des implémentations concrètes.
2.3. Les adaptateurs
Les adapters sont les implémentations concrètes de ces ports :
-
un adapter Doctrine pour
LeadRepositoryInterface; -
un adapter Mailer pour
NotifierInterface; - un adapter HTTP pour un service externe.
Ce sont eux qui connaissent le framework, la base de données, les APIs. Si demain on change d’outil, on change l’adapter, pas le domaine.
2.4. L’inversion des dépendances
Visuellement, on inverse le sens habituel :
- au lieu que le métier dépende de l’infrastructure,
- c’est l’infrastructure qui dépend du métier.
Le domaine ne connaît personne, mais tout le monde connaît le domaine.
3. Les avantages concrets en PHP/Symfony
3.1. Testabilité maximale
Avec un domaine découplé :
- on teste chaque cas d’usage en test unitaire pur, sans kernel Symfony, sans DB ;
- on injecte des fakes / mocks de ports (repo, bus, notifier) ;
- les tests sont rapides, stables, et plus proches du métier.
Résultat : une boucle de feedback rapide et un refactoring beaucoup plus serein.
3.2. Indépendance vis-à-vis du framework
En hexagonal, Symfony devient une dépendance technique, pas le centre du monde :
- monter de Symfony 5 → 6 → 7 avec moins de risque ;
- remplacer un bundle par un autre sans réécrire tout le métier ;
- brancher plusieurs interfaces (HTTP, CLI, consumer) sur les mêmes use cases.
Tu construis un produit métier, pas une “application Symfony”.
3.3. Longévité et évolutivité
Les applications métiers vivent longtemps (5, 10 ans ou plus). En hexagonal, tu peux :
- changer de base (MySQL → PostgreSQL) ;
- changer de moteur de recherche (SQL → Elasticsearch/OpenSearch) ;
- remplacer un provider de paiement ou d’email.
… sans casser ton code métier. Tu protèges l’investissement fonctionnel de l’entreprise.
4. Exemple simple en Symfony : créer un Lead
Prenons un cas d’usage classique : créer un lead dans un système métier.
4.1. Le cas d’usage (Application)
Dans la couche application, on définit un use case explicite :
namespace App\Application\Lead;
final class CreateLeadCommand
{
public function __construct(
public string $email,
public string $source,
public ?string $phone = null,
) {}
}
Mots-clés :
Vous travaillez sur un projet de transformation digitale, une architecture PHP/Symfony ou un SaaS ?
Si cet article fait écho à vos enjeux (modernisation de SI, scalabilité, APIs, organisation des équipes, micro-SaaS…), nous pouvons en discuter pour voir comment je peux vous aider concrètement.
Parler de votre projet