Une intégration cesse d’être un détail technique lorsque ses champs, ses codes d’erreur et ses règles d’accès apparaissent dans les contrôleurs, les services d’application, les modèles et les processus métier. À ce stade, changer de fournisseur, mettre à jour une API ou traiter un incident externe exige de modifier des parties de l’application qui ne devraient pas connaître ce système.
Isoler les intégrations externes en PHP consiste à établir une frontière claire : le domaine exprime ce dont il a besoin dans son propre langage et une couche d’infrastructure traduit ce besoin dans le protocole, le format et le comportement concrets du fournisseur. Il ne s’agit pas de cacher une API derrière une classe portant un autre nom, mais d’empêcher que ses décisions conditionnent toute l’application.
Quand une intégration contamine déjà l’application

Le couplage tend à croître de manière incrémentale. Une équipe consomme une API depuis un contrôleur pour résoudre une livraison urgente ; puis un autre flux réutilise le même client ; enfin, les tableaux de réponse et les exceptions du SDK deviennent des dépendances implicites du métier.
- Les cas d’utilisation reçoivent ou renvoient des tableaux contenant les noms de champs du fournisseur.
- La logique métier compare des codes externes, tels que
ERR_42ouPENDING_REVIEW. - Les contrôleurs, commandes et tâches en file d’attente construisent directement des requêtes HTTP.
- Les exceptions du SDK externe sont capturées en dehors de l’infrastructure.
- Une modification des identifiants d’accès, des endpoints ou des versions impose de modifier plusieurs modules.
- Les tests du domaine nécessitent des connexions réelles, des jetons ou des réponses simulées du fournisseur.
Ces signaux ne signifient pas qu’une réécriture complète doive être entamée. Ils indiquent en revanche qu’il est opportun de prioriser l’intégration selon son risque : criticité pour le métier, fréquence des changements du fournisseur, volume de consommateurs internes, sensibilité des données et difficulté à se remettre d’une défaillance.
Définir des contrats à partir du langage métier
Le contrat interne, également appelé port, doit décrire une capacité dont l’application a besoin, et non reproduire le catalogue d’opérations d’une API externe. Par exemple, une application de réservation peut avoir besoin de « demander une réservation », « consulter son état » et « l’annuler ». Le domaine n’a pas besoin de savoir qu’un fournisseur utilise XML, OAuth, un identifiant numérique ou une convention particulière de tentatives de reprise.
Un port peut s’exprimer sous la forme d’une interface PHP :
interface ReservationGateway
{
public function request(ReservationRequest $request): ReservationResult;
public function status(ReservationReference $reference): ReservationStatus;
public function cancel(ReservationReference $reference): void;
}Les types du contrat doivent appartenir au langage interne. ReservationRequest contient les données nécessaires à la décision métier ; il ne devrait pas inclure de champs d’authentification, d’en-têtes HTTP ni de noms hérités du fournisseur. De même, une référence interne peut encapsuler l’identité externe sans la rendre dominante dans tous les cas d’utilisation.
Les éléments d’une frontière d’intégration
Port, adaptateur et DTO interne
Le port est l’interface consommée par l’application. L’adaptateur est l’implémentation qui communique avec le système externe. Entre les deux, les DTO internes transportent les données dans une structure stable pour l’application.
L’adaptateur traduit dans les deux sens : il convertit le DTO interne en une requête spécifique et normalise la réponse en un résultat que le domaine peut interpréter. Si le fournisseur remplace guest_count par travellers, le changement doit rester contenu dans cet adaptateur.
Configuration, identifiants d’accès et transport
Les endpoints, jetons, délais d’attente, certificats et politiques de tentatives relèvent de l’infrastructure. Ils doivent être injectés via la configuration et rester en dehors des entités et des services de domaine. Il est également opportun de séparer le client HTTP ou SDK de l’adaptateur : cela facilite le remplacement de bibliothèques, l’enregistrement de la télémétrie et le test du mappage sans dépendre du transport réel.
Traduction des erreurs et états incertains
Toutes les défaillances ne reçoivent pas le même traitement. Une erreur de validation renvoyée par le fournisseur peut être récupérable pour l’utilisateur ; une défaillance d’authentification exige une intervention opérationnelle ; un timeout peut laisser un état incertain, car le fournisseur a peut-être traité la demande.
Le contrat interne doit représenter ces différences sans laisser filtrer des exceptions étrangères. Par exemple, l’adaptateur peut transformer une réponse de validation en ReservationRejected, un problème temporaire en TemporaryUnavailable et un timeout après l’envoi de la demande en UnknownSubmissionState. Ce dernier ne doit pas être traité comme une simple erreur : il peut nécessiter une consultation ultérieure par une clé d’idempotence ou une réconciliation opérationnelle.
Traduire les erreurs ne signifie pas effacer les détails. Enregistrez de manière sécurisée l’identifiant de corrélation, la cause technique et la réponse pertinente, en évitant d’exposer des secrets ou des données sensibles à l’utilisateur.
Exemple d’encapsulation d’un service de réservation
Supposons qu’un fournisseur exige une requête JSON avec des dates dans un format précis, un code d’hôtel qui lui est propre et un en-tête d’autorisation. Le cas d’utilisation interne ne devrait pas construire cette requête. Il reçoit une demande de réservation, applique ses règles et appelle ReservationGateway.
L’adaptateur ExternalReservationAdapter effectue les tâches spécifiques :
- Convertir l’identifiant interne de l’hébergement en code reconnu par le fournisseur.
- Formater les dates, les voyageurs et les préférences selon le contrat externe.
- Ajouter les identifiants d’accès et une clé d’idempotence.
- Interpréter les codes HTTP, les corps d’erreur et les états spécifiques.
- Renvoyer une référence et un état internes.
L’application conserve la règle déterminant quand une réservation est acceptable ; l’adaptateur conserve la règle indiquant comment la demander à ce fournisseur. Si un second fournisseur est intégré, le même port peut être implémenté, à condition que la capacité métier soit équivalente. Dans le cas contraire, forcer une interface commune peut masquer des différences importantes et créer des décisions ambiguës.
Comment extraire une intégration déjà couplée
Une migration sûre n’exige pas d’arrêter l’évolution du produit. Commencez par un inventaire : localisez les appels directs, les classes du SDK, les formats externes, les exceptions filtrées et les consommateurs. Identifiez d’abord les parcours critiques ou ceux qui changent le plus fréquemment.
- Introduisez une façade : créez le port et un adaptateur initial pouvant réutiliser temporairement une partie du client existant.
- Migrez les consommateurs par flux : remplacez les appels directs d’un cas d’utilisation à la fois. Évitez de conserver deux interprétations différentes d’une même erreur.
- Centralisez le mappage : retirez les conversions de champs et de codes externes des contrôleurs, services et templates.
- Ajoutez de l’observabilité : enregistrez la latence, les résultats, les erreurs normalisées et la corrélation entre la requête interne et l’appel externe.
- Retirez l’accès direct : lorsqu’il ne reste plus de consommateurs, restreignez ou supprimez le client exposé afin d’éviter les régressions.
Durant la transition, la façade ne doit pas devenir un conteneur générique de méthodes du SDK. Son objectif est de définir une frontière utile et stable, non de déplacer le couplage dans un autre dossier.
Tests et critères de validation de l’isolation
Les tests du domaine doivent utiliser des doubles du port. Ils vérifient ainsi les décisions métier sans réseau, identifiants d’accès ni comportements accidentels du fournisseur. Les tests de l’adaptateur, en revanche, doivent vérifier le mappage des demandes, réponses et erreurs par rapport à un environnement contrôlé, un serveur simulé ou des contrats documentés par le système externe.
Le résultat est vérifiable si ces critères sont respectés :
- Une modification de format, d’endpoint ou de SDK est concentrée dans l’adaptateur et sa configuration.
- Les cas d’utilisation dépendent de contrats internes, et non de clients HTTP ni de types externes.
- Les exceptions et codes du fournisseur ne traversent pas la frontière.
- Les états incertains bénéficient d’un traitement explicite, y compris l’idempotence ou une consultation ultérieure lorsque cela est nécessaire.
- Les tests métier s’exécutent avec des doubles et les tests d’intégration valident la traduction réelle.
Erreurs fréquentes avant d’intégrer un autre fournisseur

L’abstraction prématurée est un risque : ne créez pas une hiérarchie complexe pour une unique intégration stable sans besoins réels de remplacement. L’extrême opposé échoue également : répliquer toute l’API externe dans une interface interne fait hériter le domaine de sa complexité.
Avant d’intégrer, confirmez de quelle capacité le métier a besoin, qui possède chaque donnée, quelles erreurs sont actionnables, comment éviter la duplication des opérations et ce qui se passera si aucune réponse n’arrive. Définissez le port à partir de ces décisions, implémentez l’adaptateur comme traducteur et maintenez les particularités externes à la frontière. Cette discipline permet d’isoler les intégrations externes en PHP sans transformer chaque changement de fournisseur en une modification transversale de l’application.



