Una integración deja de ser un detalle técnico cuando sus campos, códigos de error y reglas de acceso aparecen en controladores, servicios de aplicación, modelos y procesos de negocio. En ese punto, cambiar de proveedor, actualizar una API o atender una incidencia externa exige modificar partes de la aplicación que no deberían conocer ese sistema.
Aislar integraciones externas en PHP consiste en establecer una frontera clara: el dominio expresa lo que necesita en su propio lenguaje y una capa de infraestructura traduce esa necesidad al protocolo, formato y comportamiento concretos del proveedor. No se trata de ocultar una API detrás de una clase con otro nombre, sino de impedir que sus decisiones condicionen toda la aplicación.
Cuándo una integración ya está contaminando la aplicación

El acoplamiento suele crecer de forma incremental. Un equipo consume una API desde un controlador para resolver una entrega urgente; después otro flujo reutiliza el mismo cliente; finalmente, los arrays de respuesta y las excepciones del SDK se convierten en dependencias implícitas del negocio.
- Los casos de uso reciben o devuelven arrays con nombres de campos del proveedor.
- La lógica de negocio compara códigos externos, como
ERR_42oPENDING_REVIEW. - Controladores, comandos y trabajos en cola construyen peticiones HTTP directamente.
- Las excepciones del SDK externo se capturan fuera de la infraestructura.
- Una modificación de credenciales, endpoints o versiones obliga a editar varios módulos.
- Las pruebas del dominio necesitan conexiones reales, tokens o respuestas simuladas del proveedor.
Estas señales no significan que deba iniciarse una reescritura completa. Sí indican que conviene priorizar la integración por su riesgo: criticidad para el negocio, frecuencia de cambios del proveedor, volumen de consumidores internos, sensibilidad de los datos y dificultad para recuperarse de un fallo.
Definir contratos desde el lenguaje del negocio
El contrato interno, también llamado puerto, debe describir una capacidad que la aplicación necesita, no una reproducción del catálogo de operaciones de una API externa. Por ejemplo, una aplicación de reservas puede necesitar “solicitar una reserva”, “consultar su estado” y “cancelarla”. No necesita que el dominio sepa que un proveedor utiliza XML, OAuth, un identificador numérico o una convención particular de reintentos.
Un puerto puede expresarse como una interfaz PHP:
interface ReservationGateway
{
public function request(ReservationRequest $request): ReservationResult;
public function status(ReservationReference $reference): ReservationStatus;
public function cancel(ReservationReference $reference): void;
}Los tipos del contrato deben pertenecer al lenguaje interno. ReservationRequest contiene los datos necesarios para la decisión de negocio; no debería incluir campos de autenticación, encabezados HTTP ni nombres heredados del proveedor. Del mismo modo, una referencia interna puede encapsular la identidad externa sin hacerla dominante en todos los casos de uso.
Las piezas de una frontera de integración
Puerto, adaptador y DTO interno
El puerto es la interfaz que consume la aplicación. El adaptador es la implementación que habla con el sistema externo. Entre ambos, los DTO internos trasladan datos con una estructura estable para la aplicación.
El adaptador traduce en ambos sentidos: convierte el DTO interno en una petición específica y normaliza la respuesta a un resultado que el dominio pueda interpretar. Si el proveedor cambia guest_count por travellers, el cambio debe quedar contenido en ese adaptador.
Configuración, credenciales y transporte
Endpoints, tokens, tiempos de espera, certificados y políticas de reintento son preocupaciones de infraestructura. Deben inyectarse mediante configuración y mantenerse fuera de entidades y servicios de dominio. También conviene separar el cliente HTTP o SDK del adaptador: facilita sustituir bibliotecas, registrar telemetría y probar el mapeo sin depender del transporte real.
Traducción de errores y estados inciertos
No todos los fallos tienen el mismo tratamiento. Un error de validación rechazado por el proveedor puede ser recuperable para el usuario; un fallo de autenticación exige intervención operativa; un tiempo de espera puede dejar un estado incierto porque el proveedor quizá procesó la solicitud.
El contrato interno debe representar estas diferencias sin filtrar excepciones ajenas. Por ejemplo, el adaptador puede transformar una respuesta de validación en ReservationRejected, un problema temporal en TemporaryUnavailable y un timeout tras enviar la solicitud en UnknownSubmissionState. Este último no debe tratarse como un simple error: puede requerir consulta posterior por una clave de idempotencia o conciliación operativa.
Traducir errores no significa borrar detalles. Registre de forma segura el identificador de correlación, la causa técnica y la respuesta relevante, evitando exponer secretos o datos sensibles al usuario.
Ejemplo de encapsulación de un servicio de reservas
Supongamos que un proveedor exige una petición JSON con fechas en un formato concreto, un código de hotel propio y una cabecera de autorización. El caso de uso interno no debería construir esa petición. Recibe una solicitud de reserva, aplica sus reglas y llama a ReservationGateway.
El adaptador ExternalReservationAdapter realiza las tareas específicas:
- Convierte el identificador interno de alojamiento al código que reconoce el proveedor.
- Formatea fechas, huéspedes y preferencias según el contrato externo.
- Añade credenciales y una clave de idempotencia.
- Interpreta códigos HTTP, cuerpos de error y estados propios.
- Devuelve una referencia y un estado internos.
La aplicación conserva la regla de cuándo una reserva es aceptable; el adaptador conserva la regla de cómo pedirla a ese proveedor. Si se incorpora un segundo proveedor, puede implementarse el mismo puerto, siempre que la capacidad de negocio sea equivalente. Si no lo es, forzar una interfaz común puede ocultar diferencias importantes y crear decisiones ambiguas.
Cómo extraer una integración ya acoplada
La migración segura no requiere detener la evolución del producto. Empiece por un inventario: localice llamadas directas, clases del SDK, formatos externos, excepciones filtradas y consumidores. Identifique primero los caminos críticos o los que cambian con mayor frecuencia.
- Introduzca una fachada: cree el puerto y un adaptador inicial que pueda reutilizar temporalmente parte del cliente existente.
- Migre consumidores por flujo: sustituya las llamadas directas de un caso de uso cada vez. Evite mantener dos interpretaciones distintas del mismo error.
- Centralice el mapeo: retire conversiones de campos y códigos externos de controladores, servicios y plantillas.
- Añada observabilidad: registre latencia, resultados, errores normalizados y correlación entre petición interna y llamada externa.
- Retire el acceso directo: cuando no queden consumidores, restrinja o elimine el cliente expuesto para evitar regresiones.
Durante la transición, la fachada no debe convertirse en un contenedor genérico de métodos del SDK. Su finalidad es definir una frontera útil y estable, no trasladar el acoplamiento a otra carpeta.
Pruebas y criterios para validar el aislamiento
Las pruebas del dominio deben usar dobles del puerto. Así verifican decisiones de negocio sin red, credenciales ni comportamientos accidentales del proveedor. Las pruebas del adaptador, en cambio, deben comprobar el mapeo de solicitudes, respuestas y errores contra un entorno controlado, un servidor simulado o contratos documentados por el sistema externo.
El resultado es verificable si se cumplen estos criterios:
- Un cambio de formato, endpoint o SDK se concentra en el adaptador y su configuración.
- Los casos de uso dependen de contratos internos, no de clientes HTTP ni tipos externos.
- Las excepciones y códigos del proveedor no atraviesan la frontera.
- Los estados inciertos tienen un tratamiento explícito, incluida idempotencia o consulta posterior cuando sea necesaria.
- Las pruebas de negocio se ejecutan con dobles y las de integración validan la traducción real.
Errores habituales antes de incorporar otro proveedor

La abstracción prematura es un riesgo: no cree una jerarquía compleja para una única integración estable sin necesidades reales de sustitución. El extremo opuesto también falla: replicar toda la API externa en una interfaz interna hace que el dominio herede su complejidad.
Antes de integrar, confirme qué capacidad necesita el negocio, quién posee cada dato, qué errores son accionables, cómo se evita la duplicidad de operaciones y qué ocurrirá si no llega respuesta. Defina el puerto con esas decisiones, implemente el adaptador como traductor y mantenga las peculiaridades externas en el borde. Esa disciplina permite aislar integraciones externas en PHP sin convertir cada cambio de proveedor en un cambio transversal de la aplicación.



