Logomark

LARAVEL

Un framework qui rend heureux
Voir cette catégorie
Vers le bas
Voir cette série
Créer un package - 1
Vendredi 3 octobre 2025 16:09

Créer un package pour Laravel n'est pas bien difficile à condition d'être organisé. J'avais écrit un article sur le sujet il y a très longtemps et il est grand temps de le rafraîchir. Des fois, le fait d'aborder ce sujet fait un peu peur avec des notions pas toujours évidentes de providers, contracts, facades, et autres fantaisies. Le but de cette nouvelle série est de vous montrer que ce n'est finalement pas bien compliqué si on respecte certaines règles et surtout si on comprend les concepts essentiels. Pour servir de support à ces articles, je vais décrire le processus complet pour réaliser ce package. J'en ai déjà décrit les grandes lignes dans un précédent article.

On se prépare

Souvent, on ne sait pas trop comment commencer. La première chose à faire est de créer une instance de Laravel qui va servir de base pour le développement :

laravel new edgetts

Ne prenez aucun startup kit et choisissez PHPUnit pour les tests. Pour la base, prenez ce que vous voulez, on ne s'en servira pas. Laissez npm compiler et c'est bon ! Si vous avez la page de départ, c'est parfait :

Maintenant qu'on a un joli Laravel 12 tout prêt, on va pouvoir implanter notre package. Créez cette structure de dossiers dans votre projet :

Voyons ça de plus près :

  • packages : le dossier pour placer tous vos packages (vous n'allez pas vous arrêter à un seul !)
  • happycoder : votre nom pour votre compte github, là j'ai choisi une appellation fantaisiste (quand vous allez déployer votre package)
  • laravel-edge-tts : la racine de votre package avec un nom qui évoque son objectif
  • src : le dossier dans lequel vous allez placer votre code principal (en gros ça équivaut à app dans Laravel)

À présent, on va initialiser composer dans notre package pour qu'il soit reconnu et chargé par le projet support, et par la suite par ceux qui vont l'installer :

E:\laragon\www\edgetts\packages\happycoder\laravel-edge-tts
composer init

  Welcome to the Composer config generator

This command will guide you through creating your composer.json config.

Package name (<vendor>/<name>) [grand/laravel-edge-tts]: happycoder/laravel-edge-tts
Description []: Edge-tts-php integration for Laravel
Author [bestmomo <colorstonic@free.fr>, n to skip]: happycoder <happy@ici.fr>
Minimum Stability []: stable
Package Type (e.g. library, project, metapackage, composer-plugin) []: laravel-package
License []: MIT

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]? no
Would you like to define your dev dependencies (require-dev) interactively [yes]? no
Add PSR-4 autoload mapping? Maps namespace "Happycoder\LaravelEdgeTts" to the entered relative path. [src/, n to skip]:

{
    "name": "happycoder/laravel-edge-tts",
    "description": "Edge-tts-php integration for Laravel",
    "type": "laravel-package",
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "Happycoder\\LaravelEdgeTts\\": "src/"
        }
    },
    "authors": [
        {
            "name": "happycoder",
            "email": "happy@ici.fr"
        }
    ],
    "minimum-stability": "stable",
    "require": {}
}

Do you confirm generation [yes]?
Composer could not detect the root package (happycoder/laravel-edge-tts) version, defaulting to '1.0.0'. See https://getcomposer.org/root-version
Generated autoload files
PSR-4 autoloading configured. Use "namespace Happycoder\LaravelEdgeTts;" in src/
Include the Composer autoloader with: require 'vendor/autoload.php';

Je vous ai reporté le processus complet pour plus de précision. On a donc du nouveau :

Voici notre composer.json actuel (j'ai juste ajouté le numéro de version) :

{
    "name": "happycoder/laravel-edge-tts",
    "description": "Edge-tts-php integration for Laravel",
    "type": "laravel-package",
    "license": "MIT",
    "version": "0.1.0",
    "autoload": {
        "psr-4": {
            "Happycoder\\LaravelEdgeTts\\": "src/"
        }
    },
    "authors": [
        {
            "name": "happycoder",
            "email": "happy@ici.fr"
        }
    ],
    "minimum-stability": "stable",
    "require": {}
}

Mais notre projet support n'est pas au courant qu'on a démarré ce package, il va falloir l'en informer.

La notion de service provider dans Laravel est importante à comprendre.

Le conteneur d'injection de dépendances (DI)

Laravel utilise un conteneur DI (basé sur Illuminate\Container\Container) pour gérer les dépendances entre classes. Son principe :

  • Éviter les couplages forts : au lieu d'instancier manuellement une classe, on demande au conteneur de la fournir
  • Centraliser la création d'objets : le conteneur sait comment construire une instance (avec quels paramètres, quelles dépendances, etc.)

Prenons un petit mauvais exemple :

class PaymentController {
    public function pay() {
        $stripe = new StripeClient('sk_test_...'); // Couplage fort + clé en dur !
        // ...
    }
}

Et maintenant le bon exemple équivalent :

// Dans StripeServiceProvider::register()
$this->app->singleton(StripeClient::class, function ($app) {
    return new StripeClient(config('services.stripe.secret')); // Clé configurée dans .env
});

// Dans PaymentController
public function __construct(private StripeClient $stripe) {} // Injection automatique !

À présent, c'est beaucoup plus flexible si, par exemple, on veut utiliser un autre fournisseur que Stripe. Pour les tests, on peut facilement mocker StripeClient. Enfin, la clé secrète se retrouve dans .env et non pas dans le code.

Le service provider

Un Service Provider est un composant qui permet de  au conteneur d'injection de dépendances (DI) de l'application.

Ça permet de faire plein de choses utiles :

  • : permet de dire à Laravel comment créer et fournir une instance d'une classe ou d'un service (API externe, logger personnalisé...)
  • Configurer une application : par exemple AuthServiceProvider configure ses politiques d'autorisation
  • : publier des fichiers de configuration, des migrations ou des assets
  • : via la méthode boot, on peut exécuter du code quand l'application démarre (ex : enregistrer des view composers, des routes, etc.)

Dans un service provider, on a deux fonctions :

  • register : pour enregistrer les liaisons (binding) dans le conteneur (DI) 
  • boot : pour exécuter du code après que toutes les liaisons ont été faites

Pour notre package, il nous faut donc créer un service provider :

Avec une coquille vide :

<?php

namespace Happycoder\LaravelEdgeTts;

use Illuminate\Support\ServiceProvider;

class EdgeTtsLaravelServiceProvider extends ServiceProvider
{
    /**
     * Register the services of the package in the IOC container.
     */
    public function register(): void
    {

    }

    /**
     * Start the services after all providers have been registered.
     */
    public function boot(): void
    {

    }
}

Il ne nous reste plus qu'à informer notre projet support. Il y a plusieurs façons de le faire, mais la plus simple est celle-ci dans le composer.json (du projet support !) :

"repositories": [
    {
        "url": "packages/happycoder/laravel-edge-tts",
        "type": "path"
    }
]

On va installer notre package dans ce projet support :

E:\laragon\www\edgetts                                                                                                                               
composer require happycoder/laravel-edge-tts                                                                                                       
./composer.json has been updated                                                                                                                     
Running composer update happycoder/laravel-edge-tts                                                                                                  
Loading composer repositories with package information                                                                                               
Updating dependencies                                                                                                                                
Lock file operations: 1 install, 0 updates, 0 removals                                                                                               
  - Locking happycoder/laravel-edge-tts (0.1.0)                                                                                                      
Writing lock file                                                                                                                                    
Installing dependencies from lock file (including require-dev)                                                                                       
Package operations: 1 install, 0 updates, 0 removals                                                                                                 
  - Installing happycoder/laravel-edge-tts (0.1.0): Junctioning from packages/happycoder/laravel-edge-tts                                            
Generating optimized autoload files                                                                                                                  
> Illuminate\Foundation\ComposerScripts::postAutoloadDump                                                                                            
> @php artisan package:discover --ansi                                                                                                               
                                                                                                                                                     
   INFO  Discovering packages.                                                                                                                       
                                                                                                                                                     
  laravel/pail ............................................................................................................................... DONE 
  laravel/sail ................................................................................................................................ DONE 
  laravel/tinker ........................................................................................................................... DONE 
  nesbot/carbon ........................................................................................................................ DONE 
  nunomaduro/collision ......................................................................................................... DONE 
  nunomaduro/termwind ...................................................................................................... DONE 
                                                                                                                                                     
81 packages you are using are looking for funding.                                                                                                   
Use the `composer fund` command to find out more!                                                                                                    
> @php artisan vendor:publish --tag=laravel-assets --ansi --force                                                                                    
                                                                                                                                                     
   INFO  No publishable resources for tag [laravel-assets].                                                                                          
                                                                                                                                                     
No security vulnerability advisories found.                                                                                                          
Using version ^0.1.0 for happycoder/laravel-edge-tts                                                                                                 

J'ai figuré en gras les éléments importants. 

Le package est désormais installé, mais ce n'est pas pour autant qu'il est chargé automatiquement ! Il nous reste une dernière étape. Dans le composer.json du package ajoutez ce code :

"extra": {
    "laravel": {
        "providers": [
            "HappyCoder\\LaravelEdgeTts\\EdgeTtsLaravelServiceProvider"
        ]
    }
}

Faite un petit :

composer update

Et pour terminer :

E:\laragon\www\edgetts
composer dump
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi

   INFO  Discovering packages.

  happycoder/laravel-edge-tts ...................................................................... DONE
  laravel/pail ................................................................................................................................ DONE
  laravel/sail ................................................................................................................................ DONE
  laravel/tinker ........................................................................................................................... DONE
  nesbot/carbon ........................................................................................................................ DONE
  nunomaduro/collision ......................................................................................................... DONE
  nunomaduro/termwind ...................................................................................................... DONE

Generated optimized autoload files containing 6188 classes

Le package est maintenant chargé et exécuté. Pour en être vraiment sûr, vous pouvez ajouter ça dans le provider :

public function boot(): void
{
    dd('Mon joli package est reconnu !');
}

Quand vous ouvrez l'application, vous obtenez :

"Mon joli package est reconnu !" // packages\happycoder\laravel-edge-tts\src\EdgeTtsLaravelServiceProvider.php:22

On a bien avancé, notre infrastructure de base est en place, il ne reste plus qu'à coder le package !

Conclusion

On a vu comment mettre en place l'infrastructure de base d'un package pour Laravel. Au passage, j'ai évoqué le conteneur de Laravel et l'intérêt des services providers. Dans le prochain article, on commencera à coder ce package.



Par bestmomo

Aucun commentaire

Article suivant : Créer un package - 2