Laravel 5

Créer un package

La version 5 de Laravel ne comporte plus de workbench pour créer un package, comme c’était le cas avec la version 4. On peut ainsi se demander comment s’y prendre à présent. La documentation n’est pas très explicite, elle nous conseille juste d’apprendre à utiliser Composer, et donc à se débrouiller comme on veut, ou comme on peut. Alors je vais dans cet article décrire une façon de procéder qui me paraît simple et efficace.

La version 5.1 de Laravel est sortie. Au niveau de l’authentification Il subsiste toute l’intendance mais on n’a plus les routes, les vues et les assets. On trouve juste des exemples de vues dans la documentation. Je trouve cette disparition un peu dommage et je vous propose donc la création un package pour générer tous les éléments qui sont présents dans la version 5.0. Plutôt que de partir sur un projet hypothétique c’est un package que j’ai créé et qui se trouve sur Packagist. Je vais juste décrire comment je l’ai créé.

Intendance de développement

La création d’un package se fait en deux temps :

  1. On crée un environnement de développement pour écrire et tester le code,
  2. On crée le package en local, on le transfère en général sur Github puis sur Packagist.

Voyons donc dans un premier temps l’environnement de développement maintenant que nous n’avons plus de workbench.

La première chose à faire est d’installer une version fraîche de Laravel 5.1. Il suffit de télécharger l’archive et d’utiliser composer install.

Ensuite j’ai créé ces dossiers :

img13

Pour créer un package il faut deux choses :

  1. un nom de « vendor », ici c’est bestmomo,
  2. un nom de package, ici c’est Scafold.

J’ai créé un dossier packages pour donner la possibilité de développer plusieurs packages et j’ai structuré les dossiers comme ils le seront dans le package définitif.

Contenu du package

Il nous faut dans ce package :

  • des routes,
  • des vues

Le code d’un package est habituellement placé dans un dossier src. Mais les vues sont un peu particulières et doivent être séparées. On en arrive ainsi à cette organisation :

img01

Dans le dossier views on va trouver les fichiers des vues :

img02

Et enfin dans le dossier src on va avoir les routes dans un dossier Http , un contrôleur dans un dossier Controllers et le service provider :

img03

C’est ici qu’on va avoir du code spécifique à prévoir pour que le package fonctionne.

Composer

Pour que notre code soit trouvé par l’application il va falloir expliquer à Composer qu’il doit prévoir l’autoload. On va donc ajouter cette ligne dans composer.json :

"psr-4": {
	"App\\": "app/",
	"Bestmomo\\Scafold\\": "packages/bestmomo/Scafold/src/"
}

Il faut évidemment prévoir un petit composer dumpautoload. Et là magiquement on obtient l’autoload psr-4 :

'Bestmomo\\Scafold\\' => array($baseDir . '/packages/bestmomo/Scafold/src'),

Les routes

Dans la version 5.0 de Laravel on a ces routes pour l’authentification :

Route::controllers([
	'auth' => 'Auth\AuthController',
	'password' => 'Auth\PasswordController',
]);

Il faut donc les reproduire dans le package. Comme ce genre de routage n’a pas trop bonne réputation j’en reviens à des routes détaillées :

Route::get('home', '\Bestmomo\Scafold\Http\Controllers\HomeController@index');

// Authentication routes...
Route::get('auth/login', 'Auth\AuthController@getLogin');
Route::post('auth/login', 'Auth\AuthController@postLogin');
Route::get('auth/logout', 'Auth\AuthController@getLogout');

// Registration routes...
Route::get('auth/register', 'Auth\AuthController@getRegister');
Route::post('auth/register', 'Auth\AuthController@postRegister');

// Password reset link request routes...
Route::get('password/email', 'Auth\PasswordController@getEmail');
Route::post('password/email', 'Auth\PasswordController@postEmail');

// Password reset routes...
Route::get('password/reset/{token}', 'Auth\PasswordController@getReset');
Route::post('password/reset', 'Auth\PasswordController@postReset');

J’ai prévu un fichier Scafold/Http/routes.php avec ce code.

Le provider

Il ne nous manque plus que le service provider ScafoldServiceProvider, le voici :

<?php namespace Bestmomo\Scafold;

use Illuminate\Support\ServiceProvider;

class ScafoldServiceProvider extends ServiceProvider{


    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = false;

    public function boot()
    {
        // Get namespace
        $nameSpace = $this->app->getNamespace();

        // Routes
        $this->app->router->group(['namespace' => $nameSpace . 'Http\Controllers'], function()
        {
            require __DIR__.'/Http/routes.php';
        });

        // Views
        $this->publishes([
            __DIR__.'/../views' => base_path('resources/views'),
            __DIR__.'/../views/auth' => base_path('resources/views/auth'),
            __DIR__.'/../views/emails' => base_path('resources/views/emails'),
        ]);
    }

    public function register() {}

}

On a ces actions dans le boot :

  • inclusion des routes qu’on a vues ci-dessus,
  • préparation de la publication des vues,

Évidemment il faut renseigner ce provider dans config/app.php :

'Bestmomo\Scafold\ScafoldServiceProvider',

La publication

Enfin il faut publier les vues et les assets avec php artisan vendor:publish.

On se retrouve alors avec les vues à leur place :

img04

Et maintenant ça fonctionne, par exemple avec l’url …/auth/login on a bien le formulaire :

img20

Github

On peut garder son package pour soi mais on peut aussi avoir envie de le partager. Github est une plateforme bien pratique pour publier des packages. Il faut commencer par créer un repository pour le package. Il faut évidemment avoir déjà un compte. Dans la page d’accueil il faut cliquer sur l’onglet des repositories, on a un bouton pour en créer un :

img22

On arrive alors sur le formulaire de création :

img23

Il faut compléter avec le nom du repository, dans mon cas scafold. On peut aussi ajouter une description, j’ai mis « To add scafold to Laravel 5.1 ». On garde évidemment Public pour le partage (notez que l’option Private n’est pas gratuite). On ne coche pas pour l’initialisation du README puisqu’on a un projet local. Il ne reste plus alors qu’à cliquer sur le bouton de création.

Lorsque le repository est créé on arrive sur une page avec des informations bien pratiques. Dans notre cas c’est :

…or push an existing repository from the command line

git remote add origin https://github.com/bestmomo/scafold.git
git push -u origin master

On garde ça dans un coin parce qu’on va en avoir besoin.

Le package

Pour compléter le package pour l’envoyer sur Github il va juste falloir ajouter deux fichiers :

img05

Voici le contenu de composer.json :

{
  "name": "bestmomo/scafold",
  "description": "To add scafold to Laravel 5.1",
  "homepage": "http://github.com/bestmomo/scafold",
  "license": "MIT",
  "authors": [
    {
      "name": "Taylor Otwell",
      "email": "taylorotwell@gmail.com"
    },
    {
      "name": "Bestmomo",
      "email": "grandheretique@free.fr"
    }
  ],
  "require": {
    "php": ">=5.4.0",
    "illuminate/support": "~5.1"
  },
  "autoload": {
    "psr-4": {
      "Bestmomo\\Scafold\\": "src/"
    }
  }
}

C’est le minimum à prévoir. Les informations sont suffisamment explicites. Il faut bien dans le nom préciser le vendor et le repository. J’ai conservé dans les auteurs Taylor puisque le code de base est de lui. Dans les requis j’ai juste mis la version de PHP ainsi que la librairie support de Laravel à la version 5.1. De toute façon le package ne sert qu’à Laravel. Il ne faut surtout pas oublier l’autoload sinon le package ne fonctionnera pas.

Pour le fichier README il doit être au format Markdown. Si vous ne le connaissez pas c’est le moment de vous y mettre ! Ça vous servira forcément ailleurs. Voilà à quoi il ressemble dans mon cas :

## Scafold ##

### Installation ###

Add Scafold to your composer.json file to require Scafold :
```
    require : {
        "laravel/framework": "5.1.*",
        "bestmomo/scafold": "dev-master"
    }
```

Update Composer :
```
    composer update
```

The next required step is to add the service provider to config/app.php :
```
    'Bestmomo\Scafold\ScafoldServiceProvider',
```

### Publish ###

The last required step is to publish views and assets in your application with :
```
    php artisan vendor:publish
```

Congratulations, you have successfully installed Scafold !

Voilà le rendu sur la page Github du repository :

img24

Envoi sur Github

La première chose à faire est d’initialiser git dans le dossier local :

git init

Il faut ensuite ajouter tous les changements, c’est  à dire en fait tous les fichiers présents :

git add --all

Et faire le premier commit :

git commit -m "First commit"

Il ne reste plus qu’à envoyer le package sur Github.

git remote add origin https://github.com/bestmomo/scafold.git
git push -u origin master

Et normalement on retrouve le tout sur Github :

img25

Là évidemment sur l’image j’ai plus de commits puisque je n’en suis pas à l’initialisation.

Si vous n’êtes pas à l’aise avec git je vous conseille l’excellent tutoriel présent sur leur site. D’autre part il existe de nombreux logiciels pour ceux qui sont allergiques à la console. Mais avec un peu d’habitude franchement ce n’est pas bien compliqué.

Packagist

Pour partager le package il va falloir maintenant le proposer sur Packagist. Pour ça il faut évidemment un compte. On a alors sur la page d’accueil un joli bouton :

img26

Et quand on clique dessus on arrive au formulaire :

img07

Il suffit d’entrer l’adresse du repository qu’on trouve sur Github :

img28

Si tout se passe bien le package est publié :

img06

Il reste une dernière étape optionnelle pour synchroniser les changements que je vous laisse découvrir !

Essai du package

Il ne reste plus qu’à essayer ce package dans un Laravel tout neuf. Il suffit pour cela de suivre les indication présentes dans le fichier README…

Autres ressources

Il existe bien entendu d’autres manières de créer un package. L’une d’entre elle que j’ai lue récemment me paraît intéressante. Elle prend le contre-pied de ce que je vous propose dans cet article. En gros la démarche consiste à commencer par créer le dépôt Github avec ce squelette pour ne pas partir de zéro. On a ainsi un fichier README, un composer.json, un fichier de license.

Ensuite il propose de soumettre immédiatement le package à Packagist en version dev-master. De prime abord j’ai trouvé la démarche un peu déplacée étant donné qu’on se retrouve sur Packagist avec un package qui ne sait rien faire, ce qui n’est pas vraiment souhaitable. l’auteur s’en défend en arguant du fait que, comme on est en dev-master, donc sans version, personne ne va utiliser ce package.

Mis à part cette étape un peu douteuse le reste devient très facile à condition d’utiliser cette méthode.

Pour être honnête je ne suis pas sûr d’utiliser un jour ce processus mais il peut être intéressant, c’est pour cette raison que je vous en fais part.

Print Friendly, PDF & Email

9 commentaires

  • guru

    Bonjour, je suis entrain de créer un package Laravel de gestion d’hotel, pour cela j’ai besoin de l’authentification d’utilisateur, mais je rencontre d’enorme difficulter car cela ne marche pas
    voici mon provider:
    app->bind(‘scarface’, function ($app){
    return new Scarface;
    });
    }

    public function boot() {
    //loading the routes file
    require __DIR__.’/Http/routes.php’;

    //define the path for the view files
    $this->loadViewsFrom(__DIR__.’/../views’, ‘scarface’);
    //defined the file which are going to be published
    $this->publishes([
    __DIR__.’/migrations/2014_10_12_000000_create_users_table.php’ => base_path(‘database/migrations/2014_10_12_000000_create_users_table.php’),
    __DIR__.’/migrations/2014_10_12_100000_create_password_resets_table.php’ => base_path(‘database/migrations/2014_10_12_100000_create_password_resets_table.php’),
    __DIR__.’/migrations/2019_07_06_150548_create_posts_table.php’ => base_path(‘database/migrations/2019_07_06_150548_create_posts_table.php’),
    __DIR__.’/migrations/2019_07_06_153820_create_prices_table.php’ => base_path(‘database/migrations/2019_07_06_153820_create_prices_table.php’),
    __DIR__.’/migrations/2019_07_06_153822_create_tags_table.php’ => base_path(‘database/migrations/2019_07_06_153822_create_tags_table.php’),
    __DIR__.’/migrations/2019_07_06_153956_create_post_tag_table.php’ => base_path(‘database/migrations/2019_07_06_153956_create_post_tag_table.php’),
    __DIR__.’/migrations/2019_07_10_155720_create_reservations_table.php’ => base_path(‘database/migrations/2019_07_10_155720_create_reservations_table.php’),
    ]);
    }
    }
    mon fichier de routes:
    name(‘home’);
    //Resource of hotel detail
    Route::resource(‘post’, ‘Jazzmastaz\Scarface\Http\Controllers\PostController’);
    //Resource of room type manager
    Route::resource(‘tag’, ‘Jazzmastaz\Scarface\Http\Controllers\TagController’);
    //Resource of price list
    Route::resource(‘price’, ‘Jazzmastaz\Scarface\Http\Controllers\PriceController’);
    //Resource of room reservation
    Route::resource(‘reservation’, ‘Jazzmastaz\Scarface\Http\Controllers\ReservationController’);

    //Route::get(‘/’, ‘Amitav\Todo\Http\Controllers\TodoController@index’);

  • FabriceLPA

    Salut à toi bestmomo,

    Je suis en train de regarder pour créer mon premier package avec L5.4 et ton article m’aide pas mal.

    Par contre, j’ai une question au niveau des dépendances. Quid si on ne souhaite pas les publier dans le dossier « packages/vendor/package » mais directement dans le dossier « vendor » à la root du projet Laravel ?
    Est-ce possible?
    Et si possible, est-ce qu’il y a moyen d’indiquer ça via le composer.json du package pour que dés que l’on fait le « composer install » initial les dépendances soient publiées directement ?

    D’avance merci 😉

      • FabriceLPA

        Après essais, ça ne solutionnait pas à 100% mon souci d’installation.
        J’ai testé la méthode proposée sur murze.be, et là tout est ok, j’ai un contexte d’installation qui est à 100% ce que l’utilisateur final aura. Peut-être pas hyper clean pour ce qui est de Packagist, mais j’ai un process de dev’ qui me convient parfaitement (et tant que tu ne publies pas les assets ou autre fichier, c’est assez simple pour faire des updates depuis le projet dans lequel je développe le package et au pire, un reset du projet de destination et c’est reparti).
        Par contre, est-il possible d’étendre voir remplacer un model déjà existant, le User model depuis un package ? Si étendre, faut-il renommer la class ou peut-on utiliser le même nom (ici User) ?
        Mon package amène une série de roles attachés au model plus quelques méthodes

Laisser un commentaire