Crear un package para Laravel

Autor: Damián Aguilar
twitter
- Creado el 20/01/2020
laravel packages php frameworks

Una buena forma de ordenar y reutilizar nuestro código de Laravel, es mediante el uso de packages. En este artículo, vamos a centrarnos en la creación y desarrollo de packages propios, pero si estás interesado en packages de terceros, aquí tienes una lista con los imprescindibles (por lo menos para mi...):

  • https://daguilar.dev/blog/laravel_packages-imprescindibles-para-laravel/

Lo primero es crear la carpeta para nuestro package. Con un Mac, entramos al terminal (yo suelo utilizar la carpeta sites para mis proyectos):

mkdir sites/my-package

Si no tenemos instalado Composer, lo instalamos:

  • https://getcomposer.org/

Ahora, nos vamos al terminal y entramos en la carpeta de nuestro package:

cd sites/my-package

E iniciamos Composer:

composer init

Ahora Composer empezará a hacernos preguntas sobre el package y el autor... podemos saltarlas o añadir la información. El resultado final, será la de la creación del archivo composer.json, que tendrá un aspecto similar a este:

{
    "name": "daguilarm/belich",
    "description": "Laravel admin dashboard",
    "license": "MIT",
    "authors": [
        {
            "name": "daguilarm",
            "email": "damian.aguilarm@gmail.com"
        }
    ],
    "require": {},
    "minimum-stability": "dev"
}

El siguiente paso es el de crear un ServiceProvider. Para ello, creamos la carpeta sites/my-package/src y le añadimos el archivo BelichServiceProvider.php o como quieras llamarlo.

Ahora es el momento de añadir a nuestro archivo composer.json, nuestro ServiceProvider y el Namespace:

{
    "name": "daguilarm/belich",
    "description": "Laravel admin dashboard",
    "license": "MIT",
    "authors": [
        {
            "name": "daguilarm",
            "email": "damian.aguilarm@gmail.com"
        }
    ],
    "extra": {
        "laravel": {
            "providers": [
                "Daguilarm\\Belich\\ServiceProvider"
            ]
        }
    },
    "autoload": {
        "psr-4": {
            "Daguilarm\\Belich\\": "src/"
        }
    },
    "require": {},
    "minimum-stability": "dev"
}

El namespace del package, sería: Daguilarm\Belich y la ubicación del ServiceProvider: Daguilarm\Belich\ServiceProvider.

Ahora nos toca configurar nuestro ServiceProvider. Este archivo debe de tener la siguiente estructura básica:

<?php

namespace Daguilarm\Belich;

use Illuminate\Support\ServiceProvider as Provider;

final class ServiceProvider extends Provider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot(): void
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register(): void
    {
        // 
    }
}

Ahora vienen las preguntas importantes:

¿Como configurar las rutas del package?

Podemos crear un método y añadir los archivos de rutas:

/**
 * Register the package routes
 *
 * @return void
 */
protected function registerRoutes(): void
{
    require_once __DIR__ . '/../routes/AuthRoutes.php';
    require_once __DIR__ . '/../routes/ResolveRoutes.php';
    ...
}

Estos archivos, los crearemos en sites/my-package/routes, y son iguales que los archivos de rutas de Laravel:

//sites/my-package/routes/AuthRoutes.php
<?php

Route::group(['middleware' => ['web']], static function (): void {

    // Authentication Routes...
    Route::get(Belich::path() . '/login', 'Daguilarm\Belich\App\Http\Controllers\Auth\LoginController@showLoginForm')->name('login');
});

Y luego, desde el método boot(), llamamos las rutas:

<?php

namespace Daguilarm\Belich;

use Illuminate\Support\ServiceProvider as Provider;

final class ServiceProvider extends Provider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot(): void
    {
        //Routes 
        $this->registerRoutes();
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register(): void
    {
        // 
    }
}

¿Como configurar los recursos y las vistas?

Vamos a utilizar la misma técnica de antes. A nuestro método boot(), le añadimos:

<?php

namespace Daguilarm\Belich;

use Illuminate\Support\ServiceProvider as Provider;

final class ServiceProvider extends Provider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot(): void
    {
        //Routes 
        $this->registerRoutes();

        //Resources 
        $this->registerResources();
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register(): void
    {
        // 
    }
}

Y nuestro nuevo método, sería así:

/**
 * Register the package resources
 *
 * @return void
 */
protected function registerResources(): void
{
    //Load the views
    $this->loadViewsFrom(__DIR__ . '/../resources/views', 'belich');
    //Load language translations...
    $this->loadTranslationsFrom(resource_path('lang/vendor/belich'), 'belich');
    $this->loadJsonTranslationsFrom(resource_path('lang/vendor/belich'), 'belich');
}

Lo que estamos haciendo, es indicarle a Laravel, en que rutas vamos a guardar nuestros recursos:

  • sites/my-package/resources/view, para nuestras vistas.
  • sites/laravel/resources/lang/vendor/belich, para nuestros archivos de idioma (la ruta es del proyecto de Laravel, no del package).

Ahora, para acceder a las vistas del package, debemos utilizar:

view('belich::path.to.the.view')

y lo mismo para los archivos de idioma:

trans('belich::path.to.the.file')

¿Como configurar las migraciones?

Seguimos la estructura anterior, y añadimos:

<?php

namespace Daguilarm\Belich;

use Illuminate\Support\ServiceProvider as Provider;

final class ServiceProvider extends Provider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot(): void
    {

        //Routes 
        $this->registerRoutes();

        //Resources 
        $this->registerResources();

        //Migrations 
        $this->registerMigrations();
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register(): void
    {
        // 
    }
}

Ahora, solo tenemos que indicar, en que directorio guardamos las migraciones de nuestro package:

//sites/my-package/database/migrations
/**
 * Register the package migrations
 *
 * @return void
 */
protected function registerMigrations(): void
{
    $this->loadMigrationsFrom(__DIR__.'/../database/migrations');
}

¿Como configurar comandos de consola?

Seguimos la estructura anterior, y añadimos:

<?php

namespace Daguilarm\Belich;

use Illuminate\Support\ServiceProvider as Provider;

final class ServiceProvider extends Provider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot(): void
    {
        //Routes 
        $this->registerRoutes();

        //Resources 
        $this->registerResources();

        //Migrations 
        $this->registerMigrations();

        //Console 
        $this->registerConsole();
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register(): void
    {
        // 
    }
}

Y creamos el método:

/**
 * Register the package console commands
 *
 * @return void
 */
protected function registerConsole(): void
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            \Daguilarm\Belich\App\Console\Commands\CardCommand::class,
            \Daguilarm\Belich\App\Console\Commands\ComponentCommand::class,
            \Daguilarm\Belich\App\Console\Commands\MetricCommand::class,
        ]);
    }
}

Extra

Si quieres saber como configurar el package para que se pueda utilizar desde Packagist:

https://daguilar.dev/blog/packages_configurar-github-webhooks-para-packagist/

Y si quieres hacer tests a un package:

https://daguilar.dev/blog/package_configurando-un-package-de-laravel-y-livewire-para-hacer-tests/