Sobre esta página
En Fundamentos del desarrollo de paquetes presentamos que basta con escribir la secciónextra.laravel en composer.json para que los service providers y las fachadas se registren automáticamente. En esta página se explica qué ocurre por debajo: cómo funciona la clase Illuminate\Foundation\PackageManifest a nivel de código fuente.
Esta página es la hermana de Fundamentos del desarrollo de paquetes. Se recomienda leer primero el uso básico de la detección automática.
Visión general del mecanismo de detección automática
La clase PackageManifest
El núcleo de la detección automática es Illuminate\Foundation\PackageManifest. A continuación se muestra un resumen de la implementación en la versión 13.x del framework.
- El manifiesto se guarda en memoria una vez cargado (propiedad
$this->manifest). Aunque llames varias veces aproviders()en una misma petición, la E/S de archivo se produce una sola vez. build()solo se ejecuta si el archivo de manifiesto no existe. En operación normal no se reconstruye en cada arranque.- El archivo real es un archivo PHP que hace
returnde un array plano (bootstrap/cache/packages.php), el formato más rápido de cargar simplemente conrequire.
Proceso de construcción del manifiesto
El métodobuild() es la parte que realmente agrega la información de los composer.json.
composer.json, se lee vendor/composer/installed.json. Es un archivo de metadatos de todos los paquetes instalados que Composer genera al ejecutar composer install / composer update. Como la sección extra del composer.json de cada paquete queda concentrada aquí, Laravel confía y lee únicamente la información gestionada por Composer.
installed.json suele estar en .gitignore, por lo que en la configuración inicial (cuando no existe vendor/) la detección automática no funciona. La caché se construye por primera vez tras finalizar composer install.Dos formas de escribir dont-discover
dont-discover puede declararse tanto en el composer.json del paquete como en el de la aplicación, pero su significado es distinto.
composer.json del paquete
composer.json de la aplicación
build(), el array $ignore se acumula mediante array_merge con el configuration['dont-discover'] de cada paquete. Es decir, técnicamente un paquete puede «desactivar la detección automática de sus propios paquetes dependientes» (por ejemplo, cuando no quieres registrar por duplicado los providers de un subpaquete que utilizas internamente). No obstante, en la práctica lo habitual es desactivarlo desde la aplicación.
Especificar * en dont-discover
Si el array que devuelve packagesToIgnore() contiene *, entonces $ignoreAll = true y se desactiva por completo la detección automática de todos los paquetes. Se utiliza cuando quieres evitar la sobrecarga de la detección automática en CI o entornos de test, o cuando quieres gestionar todo manualmente en bootstrap/providers.php.
El archivo de caché en sí
getCachedPackagesPath() devuelve la variable de entorno APP_PACKAGES_CACHE si está definida y, en caso contrario, bootstrap/cache/packages.php.
return de un array asociativo sencillo.
php artisan package:discover qué paquetes se han detectado.
Cuándo se reconstruye la caché
Illuminate\Foundation\ComposerScripts engancha tres eventos de Composer y todos llaman al mismo clearCompiled().
composer install, composer update o composer dump-autoload, la caché de configuración, la de servicios y la de paquetes se eliminan de golpe. La próxima vez que arranque Laravel se ejecutará PackageManifest::build() y se reconstruirá a partir del estado más reciente de installed.json.
Este es el comportamiento estándar de un proyecto Laravel, registrado en la sección scripts de composer.json.
composer.json de una app Laravel (extracto)
Reconstrucción manual con php artisan package:discover
Si la caché sigue desactualizada o si modificas vendor/ directamente sin pasar por Composer, puedes reconstruirla manualmente con el comando package:discover.
$manifest->build() e imprime el resultado; apenas tiene lógica específica de comando. En situaciones donde no se disparan los eventos de Composer, como cuando usas composer install --no-scripts en un pipeline de CI, necesitas invocar este comando explícitamente.
Precauciones al desplegar
En producción es habitual ejecutarcomposer install --no-dev --optimize-autoloader, pero si añades --no-scripts la caché de paquetes no se actualiza. Es más seguro incluir un paso explícito de reconstrucción en el script de despliegue.
package:discover antes que config:cache. Si la caché de configuración se genera primero, es posible que la configuración de paquetes añadida posteriormente (por ejemplo, la registrada con mergeConfigFrom) no se refleje.
Resumen
- La detección automática no funciona sobre el contenido estático de
composer.json, sino leyendo elvendor/composer/installed.jsonque genera Composer. - El resultado se guarda en
bootstrap/cache/packages.phpcomo un array PHP plano y se carga de forma muy rápida simplemente conrequire. - La caché se elimina automáticamente en los eventos de
composer install/update/dump-autoloady se reconstruye en el siguiente arranque. - En entornos donde ejecutas Composer con
--no-scripts, es necesario invocar explícitamentephp artisan package:discover. - Si añades
*adont-discover, puedes desactivar por completo la detección automática.
Páginas relacionadas
- Fundamentos del desarrollo de paquetes — uso básico de los service providers y
extra.laravel. - Service providers diferidos — optimizar el momento en que se cargan los providers detectados.
- Pruebas de paquetes con Orchestra Testbench — el comando
package:discoverexclusivo de Testbench.