# Desarrollo de Paquetes

# Introducción

Los paquetes son la forma principal de agregar funcionalidad a Laravel. Los paquetes pueden ser cualquier cosa, desde una estupenda manera de trabajar con fechas como Carbon, o un framework completo de pruebas BDD como Behat.

Hay diferentes tipos de paquetes. Algunos paquetes son independientes, lo que significa que funcionan con cualquier framework de PHP. Carbon y Behat son ejemplos de paquetes independientes. Cualquiera de estos paquetes se puede usar con Laravel simplemente solicitándolos en el archivo composer.json.

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

# Una nota sobre facades

Al escribir una aplicación Laravel, generalmente no importa si usas interfaces o facades ya que ambos brindan niveles esencialmente iguales de capacidad de pruebas. Sin embargo, al escribir paquetes, tu paquete normalmente no tendrá acceso a todos las funciones helpers de prueba de Laravel. Si deseas escribir pruebas para el paquete como si existiera dentro de una típica aplicación Laravel 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 Laravel debe cargar. Cuando alguien instala tu paquete normalmente querrás que tu proveedor de servicio sea incluido en esta lista. En lugar de requerir que los usuarios agreguen manualmente su proveedor de servicios a la lista, puede 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 los facades que desees registrar:

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

Una vez que tu paquete se haya configurado para su descubrimiento, Laravel registrará automáticamente sus proveedores de servicios y facades cuando esté instalado, creando una experiencia de instalación conveniente para los usuarios de tu paquete.

# Exclusión del descubrimiento de paquetes

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

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

Puede deshabilitar el descubrimiento de paquetes para todos los paquetes que usan 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 la conexión entre tu paquete y Laravel. Un proveedor de servicios es responsable de enlazar cosas a Laravel con el Contenedor de Servicios e informar a Laravel dónde cargar los recursos del paquete como vistas y archivos de configuración y de configuración regional.

Un Proveedor de Servicios extiende de la clase Illuminate\Support\ServiceProvider y contiene dos métodos: register y boot. La clase base ServiceProvider está ubicada en illuminate/support, donde debemos especificar todas las dependencias de nuestro paquete. Para obtener más información sobre la estructura y el propósito de los proveedores de servicios, visita su documentación.

# Recursos

# Configuración

Por lo general, deberás publicar el archivo de configuración de tu paquete en el propio directorio config de la aplicación. Esto permitirá a los usuarios anular fácilmente sus opciones de configuración predeterminadas. Para permitir que se publiquen sus archivos de configuración, debes llamar al método publishes desde el método boot de tu proveedor de servicios:

/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
    $this->publishes([
        __DIR__.'/path/to/config/courier.php' => config_path('courier.php'),
    ]);
}

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

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

Nota

No debes definir funciones anónimas en tus archivos de configuración ya que no se pueden serializar correctamente cuando los usuarios ejecutan el comando Artisan config:cache.

# Configuración predeterminada del paquete

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

/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
    $this->mergeConfigFrom(
        __DIR__.'/path/to/config/courier.php', 'courier'
    );
}

Nota

Este método solo combina el primer nivel de la matriz de configuración. Si los usuarios definen parcialmente una matriz de configuración multidimensional las opciones faltantes no se fusionarán.

# Rutas

Si tu paquete contiene rutas, puede cargarlas usando el método loadRoutesFrom. Este método determinará automáticamente si las rutas de la aplicación se almacenan en caché y no cargarán el archivo de rutas si las rutas ya se han almacenado en caché:

/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
    $this->loadRoutesFrom(__DIR__.'/routes.php');
}

# Migraciones

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

/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
    $this->loadMigrationsFrom(__DIR__.'/path/to/migrations');
}

Una vez que se hayan registrado las migraciones de tu paquete, éstas se ejecutarán automáticamente cuando se utilize el comando php artisan migrate. Cabe destacar que no es necesario exportarlas al directorio principal de las migraciones en la aplicación.

# Traducciones

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

/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
    $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier');
}

Las traducciones de paquetes se referencian usando la convención de sintaxis package::file.line. Por lo tanto, puedes cargar la línea welcome del paquete courier del archivo messages de la siguiente manera:

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

# Publicación de traducciones

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

/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
    $this->loadTranslationsFrom(__DIR__.'/path/to/translations', 'courier');

    $this->publishes([
        __DIR__.'/path/to/translations' => resource_path('lang/vendor/courier'),
    ]);
}

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

# Vistas

Para registrar las vistas de tu paquete con Laravel necesitas decirle a Laravel dónde están ubicadas. Puedes hacerlo utilizando el método loadViewsFrom del proveedor de servicios. El método loadViewsFrom acepta dos argumentos: la ruta a sus plantillas de vista y el nombre de tu paquete. Por ejemplo, si el nombre de tu paquete es courier, debe agregar lo siguiente al método boot de tu proveedor de servicios:

/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
    $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier');
}

Las vistas de paquete se referencian usando la convención de sintaxis package::view. Entonces, una vez que tu ruta de vista se registra en un proveedor de servicios, puedes cargar la vista admin del paquete courier de la siguiente manera:

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

# Desactivar vistas del paquete

Cuando utilizas el método loadViewsFrom, Laravel en realidad registra dos ubicaciones para sus vistas: el directorio resources/views/vendor de la aplicación y el directorio que tu especificas. Entonces, usando el ejemplo courier, Laravel primero comprobará si el desarrollador ha proporcionado una versión personalizada de la vista en resources/views/vendor/courier. Entonces, si la vista no se ha personalizado, Laravel buscará en el directorio de las vistas del paquete que has colocado en el método loadViewsFrom. Esto facilita a los usuarios del paquete personalizar o anular las vistas de tu paquete.

# Publicación de vistas

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

/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
    $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier');

    $this->publishes([
        __DIR__.'/path/to/views' => resource_path('views/vendor/courier'),
    ]);
}

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

# Comandos

Para registrar los comandos Artisan de tu paquete con Laravel puedes usar el método commands. Este método espera un arreglo con los nombres de clases de comando. Una vez que los comandos han sido registrados, puedes ejecutarlos usando Artisan CLI:

/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            FooCommand::class,
            BarCommand::class,
        ]);
    }
}

# Archivos públicos

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

/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
    $this->publishes([
        __DIR__.'/path/to/assets' => public_path('vendor/courier'),
    ], 'public');
}

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

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

# Publicar grupos de archivos

Es posible que desees publicar grupos de archivos y recursos de paquetes por separado. Por ejemplo, es posible que desees permitir que los usuarios publiquen los archivos de configuración de su paquete sin verse obligados a publicar los archivos de tu paquete. Puede hacer esto "etiquetándolos" cuando llames al método publishes del proveedor de servicios de un paquete. Por ejemplo, usemos etiquetas para definir dos grupos de publicación en el método boot de un proveedor de servicios de paquetes:

/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
    $this->publishes([
        __DIR__.'/../config/package.php' => config_path('package.php')
    ], 'config');

    $this->publishes([
        __DIR__.'/../database/migrations/' => database_path('migrations')
    ], 'migrations');
}

Ahora tus usuarios pueden publicar estos grupos por separado al hacer referencia a su etiqueta cuando ejecuten el comando vendor:publish:

php artisan vendor:publish --tag=config