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 initWelcome 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 []: MITDefine 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 --ansiINFO Discovering packages.
happycoder/laravel-edge-tts ...................................................................... DONE
laravel/pail ................................................................................................................................ DONE
laravel/sail ................................................................................................................................ DONE
laravel/tinker ........................................................................................................................... DONE
nesbot/carbon ........................................................................................................................ DONE
nunomaduro/collision ......................................................................................................... DONE
nunomaduro/termwind ...................................................................................................... DONEGenerated 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