1. Profundizando
  2. Desarrollo de Paquetes

Introducción

Los paquetes son la forma principal de agregar funcionalidad a Laravel. Los paquetes pueden ser cualquier cosa, desde una excelente forma de trabajar con fechas como Carbon hasta un paquete que te permite asociar archivos con modelos Eloquent como Laravel Media Library de Spatie.

Existen diferentes tipos de paquetes. Algunos paquetes son independientes, lo que significa que funcionan con cualquier framework PHP. Carbon y PHPUnit son ejemplos de paquetes independientes. Cualquiera de estos paquetes se puede utilizar con Laravel al requerirlos en tu archivo composer.json.

Por otro lado, otros paquetes están destinados específicamente para su uso con Laravel. Estos paquetes pueden tener rutas, controladores, vistas y configuración específicamente diseñados para mejorar una aplicación de Laravel. Esta guía cubre principalmente el desarrollo de aquellos paquetes que son específicos de Laravel.

Una nota sobre las facades

Al escribir una aplicación Laravel, generalmente no importa si usas contratos o fachadas, ya que ambos proporcionan niveles esencialmente iguales de prueba. Sin embargo, al escribir paquetes, tu paquete normalmente no tendrá acceso a todas las ayudas de prueba de Laravel. Si deseas poder escribir tus pruebas de paquete como si el paquete estuviera instalado dentro de una aplicación Laravel típica, puedes usar el paquete Orchestral Testbench.

Descubrimiento de paquetes

En el archivo de configuración config/app.php de una aplicación Laravel, la opción providers define una lista de proveedores de servicios que deben cargarse en Laravel. Cuando alguien instala tu paquete, normalmente querrás que tu proveedor de servicios se incluya en esta lista. En lugar de requerir a los usuarios que añadan manualmente tu proveedor de servicios a la lista, puedes definir el proveedor en la sección extra del archivo composer.json de tu paquete. Además de los proveedores de servicios, también puedes enumerar cualquier fachada que te gustaría que se registrara:

"extra": {
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},

Una vez que tu paquete haya sido configurado para ser descubierto, Laravel registrará automáticamente sus proveedores de servicios y fachadas cuando se instale, creando una experiencia de instalación conveniente para los usuarios de tu paquete.

Exclusión del descubrimiento de paquetes

Si eres el usuario de un paquete y deseas deshabilitar el descubrimiento de paquetes, puedes listar el nombre del paquete en la sección extra del archivo composer.json de tu aplicación:

"extra": {
"laravel": {
"dont-discover": [
"barryvdh/laravel-debugbar"
]
}
},

Puedes deshabilitar el descubrimiento de paquetes para todos los paquetes utilizando el carácter * dentro de la directiva dont-discover de tu aplicación:

"extra": {
"laravel": {
"dont-discover": [
"*"
]
}
},

Proveedores de servicios

Los proveedores de servicios son el punto de conexión entre tu paquete y Laravel. Un proveedor de servicios es responsable de vincular cosas en el contenedor de servicios de Laravel e informar a Laravel dónde cargar recursos del paquete, como vistas, configuración y archivos de idioma.

Un proveedor de servicios extiende la clase Illuminate\Support\ServiceProvider y contiene dos métodos: register y boot. La clase base ServiceProvider se encuentra en el paquete Composer illuminate/support, que debes agregar a las dependencias de tu propio paquete. Para obtener más información sobre la estructura y el propósito de los proveedores de servicios, consulta su documentación.

Recursos

Configuración

Normalmente, necesitarás publicar el archivo de configuración de tu paquete en el directorio config de la aplicación. Esto permitirá a los usuarios de tu paquete anular fácilmente las opciones de configuración predeterminadas. Para permitir que tus archivos de configuración se publiquen, llama al método publishes desde el método boot de tu proveedor de servicios:

/**
* Iniciar cualquier servicio de paquete.
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../config/courier.php' => config_path('courier.php'),
]);
}

Ahora, cuando los usuarios de tu paquete ejecuten el comando vendor:publish de Laravel, tu archivo se copiará a la ubicación de publicación especificada. Una vez que tu configuración haya sido publicada, sus valores se pueden acceder como cualquier otro archivo de configuración:

$value = config('courier.option');

Advertencia No debes definir cierres en tus archivos de configuración. No se pueden serializar correctamente cuando los usuarios ejecutan el comando config:cache de Artisan.

Configuración predeterminada del paquete

También puedes fusionar tu propio archivo de configuración del paquete con la copia publicada de la aplicación. Esto permitirá a tus usuarios definir solo las opciones que realmente desean anular en la copia publicada del archivo de configuración. Para fusionar los valores del archivo de configuración, utiliza el método mergeConfigFrom dentro del método register de tu proveedor de servicios.

El método mergeConfigFrom acepta la ruta del archivo de configuración de tu paquete como su primer argumento y el nombre de la copia del archivo de configuración de la aplicación como su segundo argumento:

/**
* Registrar cualquier servicio de la aplicación.
*/
public function register(): void
{
$this->mergeConfigFrom(
__DIR__.'/../config/courier.php', 'courier'
);
}

Advertencia Este método solo fusiona el primer nivel del array de configuración. Si tus usuarios definen parcialmente un array de configuración multidimensional, las opciones faltantes no se fusionarán.

Rutas

Si tu paquete contiene rutas, puedes cargarlas utilizando el método loadRoutesFrom. Este método determinará automáticamente si las rutas de la aplicación están en caché y no cargará tu archivo de rutas si estas ya están en caché:

/**
* Iniciar cualquier servicio de paquete.
*/
public function boot(): void
{
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
}

Migraciones

Si tu paquete contiene migraciones de base de datos, puedes usar el método loadMigrationsFrom para informar a Laravel cómo cargarlas. El método loadMigrationsFrom acepta la ruta de las migraciones de tu paquete como su único argumento:

/**
* Iniciar cualquier servicio de paquete.
*/
public function boot(): void
{
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
}

Una vez que las migraciones de tu paquete hayan sido registradas, se ejecutarán automáticamente cuando se ejecute el comando php artisan migrate. No necesitas exportarlas al directorio database/migrations de la aplicación.

Archivos de idioma

Si tu paquete contiene archivos de idioma, puedes usar el método loadTranslationsFrom para informar a Laravel cómo cargarlos. Por ejemplo, si tu paquete se llama courier, debes agregar lo siguiente al método boot de tu proveedor de servicios:

/**
* Iniciar cualquier servicio de paquete.
*/
public function boot(): void
{
$this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
}

Las líneas de traducción del paquete se hacen referencia utilizando la convención de sintaxis package::file.line. Así que puedes cargar la línea welcome del paquete courier desde el archivo messages así:

echo trans('courier::messages.welcome');

Publicación de archivos de idioma

Si deseas publicar los archivos de idioma de tu paquete en el directorio lang/vendor de la aplicación, puedes usar el método publishes del proveedor de servicios. El método publishes acepta una matriz de rutas de paquetes y sus ubicaciones de publicación deseadas. Por ejemplo, para publicar los archivos de idioma del paquete courier, puedes hacer lo siguiente:

/**
* Iniciar cualquier servicio de paquete.
*/
public function boot(): void
{
$this->loadTranslationsFrom(__DIR__.'/../lang', 'courier');
 
$this->publishes([
__DIR__.'/../lang' => $this->app->langPath('vendor/courier'),
]);
}

Ahora, cuando los usuarios de tu paquete ejecuten el comando Artisan vendor:publish de Laravel, los archivos de idioma de tu paquete se publicarán en la ubicación de publicación especificada.

Vistas

Para registrar las vistas de tu paquete en Laravel, debes indicarle a Laravel dónde se encuentran las vistas. Puedes hacer esto mediante el método loadViewsFrom del proveedor de servicios. El método loadViewsFrom acepta dos argumentos: la ruta a tus plantillas de vista y el nombre de tu paquete. Por ejemplo, si el nombre de tu paquete es courier, agregarías lo siguiente al método boot de tu proveedor de servicios:

/**
* Iniciar cualquier servicio de paquete.
*/
public function boot(): void
{
$this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
}

Las vistas del paquete se hacen referencia utilizando la convención de sintaxis package::view. Así que, una vez que se registra la ruta de tu vista en un proveedor de servicios, puedes cargar la vista dashboard del paquete courier así:

Route::get('/dashboard', function () {
return view('courier::dashboard');
});

Anulando las vistas del paquete

Cuando usas el método loadViewsFrom, Laravel registra en realidad dos ubicaciones para tus vistas: el directorio resources/views/vendor de la aplicación y el directorio que especificas para las vistas de tu paquete en tu llamada a loadViewsFrom. Esto facilita que los usuarios del paquete personalicen o anulen las vistas de tu paquete.

Publicación de vistas

Si deseas que tus vistas estén disponibles para su publicación en el directorio resources/views/vendor de la aplicación, puedes usar el método publishes del proveedor de servicios. El método publishes acepta una matriz de rutas de vistas de paquetes y sus ubicaciones de publicación deseadas:

/**
* Iniciar los servicios del paquete.
*/
public function boot(): void
{
$this->loadViewsFrom(__DIR__.'/../resources/views', 'courier');
 
$this->publishes([
__DIR__.'/../resources/views' => resource_path('views/vendor/courier'),
]);
}

Ahora, cuando los usuarios de tu paquete ejecuten el comando Artisan vendor:publish de Laravel, las vistas de tu paquete se copiarán en la ubicación de publicación especificada.

Componentes de vista

Si estás construyendo un paquete que utiliza componentes Blade o que coloca componentes en directorios no convencionales, deberás registrar manualmente la clase de tu componente y su alias de etiqueta HTML para que Laravel sepa dónde encontrar el componente. Normalmente, registrarías tus componentes en el método boot del proveedor de servicios de tu paquete:

use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;
 
/**
* Iniciar los servicios de tu paquete.
*/
public function boot(): void
{
Blade::component('package-alert', AlertComponent::class);
}

Una vez que tu componente ha sido registrado, se puede renderizar usando su alias de etiqueta:

<x-package-alert/>

Carga automática de componentes del paquete

Alternativamente, puedes usar el método componentNamespace para cargar automáticamente las clases de componentes por convención. Por ejemplo, un paquete Nightshade podría tener componentes Calendar y ColorPicker que residen dentro del espacio de nombres Nightshade\Views\Components:

use Illuminate\Support\Facades\Blade;
 
/**
* Iniciar los servicios de tu paquete.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}

Esto permitirá el uso de componentes de paquete por su espacio de nombres de proveedor utilizando la sintaxis package-name:::

<x-nightshade::calendar />
<x-nightshade::color-picker />

Blade detectará automáticamente la clase vinculada a este componente mediante el formato de mayúscula y minúscula del nombre del componente. También se admiten subdirectorios mediante la notación de "punto".

Componentes anónimos

Si tu paquete contiene componentes anónimos, deben colocarse dentro de un directorio components del directorio de "vistas" de tu paquete (como se especifica en el método loadViewsFrom). Luego, puedes renderizarlos prefijando el nombre del componente con el espacio de nombres de la vista de tu paquete:

<x-courier::alert />

Comando Artisan "Acerca de"

El comando Artisan about incorporado en Laravel proporciona un resumen del entorno y la configuración de la aplicación. Los paquetes pueden agregar información adicional a la salida de este comando mediante la clase AboutCommand. Normalmente, esta información se puede agregar desde el método boot de tu proveedor de servicios de paquetes:

use Illuminate\Foundation\Console\AboutCommand;
 
/**
* Iniciar cualquier servicio de la aplicación.
*/
public function boot(): void
{
AboutCommand::add('My Package', fn () => ['Version' => '1.0.0']);
}

Comandos

Para registrar los comandos Artisan de tu paquete en Laravel, puedes usar el método commands. Este método espera una matriz de nombres de clase de comandos. Una vez que los comandos han sido registrados, puedes ejecutarlos usando la CLI de Artisan:

use Courier\Console\Commands\InstallCommand;
use Courier\Console\Commands\NetworkCommand;
 
/**
* Iniciar cualquier servicio de paquete.
*/
public function boot(): void
{
if ($this->app->runningInConsole()) {
$this->commands([
InstallCommand::class,
NetworkCommand::class,
]);
}
}

Activos públicos

Tu paquete puede tener activos como JavaScript, CSS e imágenes. Para publicar estos activos en el directorio public de la aplicación, utiliza el método publishes del proveedor de servicios. En este ejemplo, también agregaremos una etiqueta de grupo de activos public, que se puede utilizar para publicar fácilmente grupos de activos relacionados:

/**
* Iniciar cualquier servicio de paquete.
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../public' => public_path('vendor/courier'),
], 'public');
}

Ahora, cuando los usuarios de tu paquete ejecuten el comando vendor:publish, tus activos se copiarán en la ubicación de publicación especificada. Dado que los usuarios normalmente necesitarán sobrescribir los activos cada vez que se actualice el paquete, puedes usar la bandera --force:

php artisan vendor:publish --tag=public --force

Publicación de grupos de archivos

Es posible que desees publicar grupos de activos y recursos de paquetes por separado. Por ejemplo, es posible que desees permitir a tus usuarios publicar los archivos de configuración de tu paquete sin verse obligados a publicar los activos de tu paquete. Puedes hacer esto "etiquetándolos" al llamar al método publishes desde el proveedor de servicios de tu paquete. Por ejemplo, usemos etiquetas para definir dos grupos de publicación para el paquete courier (courier-config y courier-migrations) en el método boot del proveedor de servicios del paquete:

/**
* Iniciar cualquier servicio de paquete.
*/
public function boot(): void
{
$this->publishes([
__DIR__.'/../config/package.php' => config_path('package.php')
], 'courier-config');
 
$this->publishes([
__DIR__.'/../database/migrations/' => database_path('migrations')
], 'courier-migrations');
}

Ahora, tus usuarios pueden publicar estos grupos por separado haciendo referencia a su etiqueta al ejecutar el comando vendor:publish:

php artisan vendor:publish --tag=courier-config