Saltar al contenido principal
Para extender las conexiones de base de datos desde un paquete, separa el registro de la lógica de creación de la selección de la conexión que se usará. Diséñalo de modo que la simple instalación no reemplace la conexión predeterminada de la aplicación ni todas las conexiones MySQL. Esta página se basa en la revisión del código fuente oficial de Laravel Framework v13.40.0. Para lo básico de la configuración de conexiones, consulta Configuración de la base de datos, y para la carga de providers, Descubrimiento de paquetes.

Elegir el punto de extensión

La creación de conexiones de base de datos ofrece puntos de extensión con alcances distintos. El valor devuelto por el callback que pasas a DB::extend() no es un PDO ni un Query Builder, sino un Illuminate\Database\Connection. DatabaseManager::configure() exige esta clase.
El extend() de la base de datos no sigue la misma convención de llamada que el Illuminate\Support\Manager común. El primer argumento del callback no es el contenedor de la aplicación, sino el array de configuración de la conexión. No reutilices tal cual los ejemplos de extensión de otros drivers.

La extensión por nombre de conexión tiene prioridad sobre el nombre de driver

DatabaseManager::makeConnection() obtiene la configuración y luego elige la lógica de creación en el siguiente orden.
  • DB::extend('reporting', ...) se aplica a database.connections.reporting.
  • DB::extend('mysql', ...) se aplica a las conexiones cuyo driver es mysql y que no tienen una extensión por nombre de conexión.
  • Ambos usan el mismo registro de extensiones. Ten en cuenta también los conflictos entre nombres de conexión y nombres de driver, y usa nombres propios del paquete.
  • extend() no crea el array de configuración. Si solo registras la extensión y no existe la configuración de la conexión con ese nombre, se lanzará una excepción.

Seleccionar explícitamente un nombre de driver propio

El siguiente es un ejemplo mínimo que conecta el nombre propio acme-sqlite con la creación de una conexión SQLite estándar. No es un ejemplo de implementación de un nuevo protocolo de BD ni de un dialecto SQL. Muestra la frontera entre el registro y la selección al distribuir un adaptador propio. Se asume una estructura en la que Acme\DatabaseBridge\ corresponde a src/ mediante PSR-4 de Composer, y el archivo se coloca en src/DatabaseBridgeServiceProvider.php.
db.factory es el binding del ConnectionFactory compartido por Laravel. Como se llama directamente al Factory estándar, no se vuelve a la selección de extensiones del DatabaseManager y se puede reutilizar la creación diferida del PDO y de la Connection de SQLite. Este callback se ejecuta la primera vez que se resuelve la conexión. El boot() del provider solo registra la lógica de creación y no ejecuta pruebas de conexión ni migraciones. Como provider normal no diferido, haz que se cargue antes de que la conexión objetivo se resuelva por primera vez. La aplicación que lo usa añade la conexión al array connections existente en config/database.php. No cambia el valor predeterminado default.
Prepara el archivo SQLite de antemano y comprueba los permisos de escritura antes de usarlo. No diseñes el paquete para que cree el archivo con solo cargarse.
Lo que el usuario pasa es el nombre de conexión acme_reports, no el nombre de driver acme-sqlite. En el ejemplo, driver se convierte a sqlite antes de pasarlo al Factory, por lo que getDriverName() tras la creación también devuelve sqlite.
Si vuelves a llamar a DB::connection($name) dentro del resolver, regresas a la creación de la misma conexión, que todavía no está retenida. Para evitar la recursión, crea la Connection con el Factory o con tu propio adaptador.

Reemplazar por una subclase de Connection es otro alcance

Para reemplazar la propia clase Connection de un driver existente, existe Connection::resolverFor(). El callback puede recibir una Closure que crea el PDO de forma diferida, en lugar de un PDO ya conectado. Sin embargo, este registro se guarda en una propiedad estática de la clase Connection. Si lo registras para sqlite, afectará a todas las conexiones SQLite nuevas creadas por el Factory estándar, incluido el ejemplo acme-sqlite anterior. No puede tratarse como un reemplazo para un único nombre de conexión.
  • En el callback, devuelve una subclase de Connection para la BD objetivo. Con la Connection base por sí sola no se conservan el Grammar, el Processor y demás elementos propios de la BD.
  • El Factory separa createConnector() de createConnection(). Registrar solo resolverFor() no proporciona un conector PDO para un driver desconocido.
  • Si el resolver propio de DB::extend() no usa el Factory estándar, tampoco pasa por la comprobación de resolverFor() dentro del Factory.
  • Volver a registrar el mismo driver lo sobrescribe. Comprueba los conflictos con otros paquetes y que no se arrastre entre pruebas dentro del mismo proceso PHP.
Los paquetes que quieran limitar el impacto deberían considerar primero DB::extend() con un nombre de conexión o de driver propio.

Distinguir reconnect y purge

El DatabaseManager retiene las Connection creadas por nombre de conexión. Aunque cambies la configuración o el resolver, los cambios no se reflejan automáticamente en las conexiones ya creadas. En particular, reconnect() no es una API que reemplace por completo la clase o el array de configuración de la Connection retenida. Si quieres reflejar cambios en la clase extendida o en la configuración de la conexión, ejecuta purge() en un momento seguro sin transacciones en curso y luego obtén una nueva conexión.
purge() no sustituye por la nueva las referencias a la Connection que retengan otros servicios o variables. Además, ::read, ::write y ::direct en el nombre de conexión son claves de retención distintas, así que no asumas que purgar el nombre base las elimina todas a la vez.No reescribas a la ligera la configuración de una conexión compartida en ejecución, por ejemplo para cambiar de tenant. En workers de larga duración, comprueba no solo la actualización de la caché de configuración, sino también el reinicio del proceso y el impacto sobre los servicios retenidos.

Probar el registro y la creación del paquete

Con Orchestra Testbench, carga el provider y selecciona realmente el driver propio. El siguiente es un ejemplo de tests/DatabaseBridgeTest.php. El entorno de ejecución necesita PDO y el driver de SQLite.
Como :memory: pierde su contenido al desconectarse, esta prueba no espera que se conserven tablas ni datos. En un paquete real, añade también lo siguiente:
  • Que el resolver por nombre de conexión tenga prioridad sobre el resolver por nombre de driver.
  • Que volver a registrar el mismo nombre y forgetExtension() no reemplacen las Connection ya creadas.
  • Las excepciones cuando falta configuración obligatoria y el comportamiento cuando falla la conexión.
  • Las funciones que te comprometes a ofrecer, como migraciones, transacciones o separación read/write en las BD compatibles.
  • Que el registro y el estado de las conexiones no se mezclen en workers de larga duración ni al combinarse con varios paquetes.

Puntos de comprobación para el mantenimiento

  • ¿Se activa mediante un nombre propio (opt-in) sin sobrescribir en silencio la conexión predeterminada ni los drivers integrados?
  • ¿Evitas meter Closures u objetos de conexión en la caché de configuración y colocas la lógica de creación en el provider?
  • ¿Gestionas los destinos de conexión y las credenciales como configuración de aplicación de confianza?
  • ¿Has vuelto a comprobar los argumentos de extend(), el orden de creación del Factory y lo que transfiere reconnect() en las versiones de Laravel soportadas?
  • ¿Indicas a los usuarios el procedimiento de regeneración tras cambiar la configuración y el reinicio de los workers?

Páginas relacionadas

Fuentes primarias consultadas

Última modificación el 3 de noviembre de 2026