Paulund
2017-11-14 #laravel

How To Create Your Own Laravel Package

In this tutorial we're going to learn the how and why we will build a Laravel package. Laravel packages are one of my favourite features of using Laravel, if you come from a WordPress background think of them as plugins for your Laravel application. They allow you to quickly add additional functionality to your Laravel application just by using composer. If you haven't used composer before have a look at this article explaining how to get started with composer.

Composer is a dependency manager for PHP, which we will use to bring in our own Laravel Package. Packages come in different forms, some can be stand alone packages, meaning they will work with any PHP application whereas some might be dependent on having Laravel installed. You'll find this information inside the packages composer.json file.

Why Use Laravel Packages

Before we get started it's important to understand the benefits of using Laravel packages in your workflow. The best way to think about these are for reusable bits of code that you can use on any project. If you think about all the functionality you normally need in the majority of your projects you'll quickly see overlaps of code that you always do. One of the most common bits of code that people will use on many projects is a user management functionality, allowing you to manage the users, roles and permissions.

There are already many Laravel user management packages that you can get from github, but I recommend building your own to start with to understand the benefits of packages. Once this package has been built you can reuse this code on any of your future projects, therefore if you start a new project to get the user management functionality in your application all you have to do is require in your package and you have all the same functionality.

A contact form might be a page you create you all your projects, simply create a package that has a contact form view file, a controller to process the request and include this in your projects. You can now reuse the same contact form logic on every project and change the styling with your project CSS file. You might have common Laravel code you use in every project, maybe you have a BaseController class, a BaseModel or common traits that you can reuse. Why not create a Laravel common package which you can bring in on all your projects. Packages are a great way to speed up your development by allowing you to easily reuse your code. They're also a great way of distributing new functionality to all your projects.

If you create a new class in your Laravel common package, all you have to do is composer update in your projects and you get this new functionality. The more projects you work on the more places you'll see the need to create a package for reusable functionality. The more packages you have available to you the quicker any new projects will be. Wouldn't it be great to start a new project, include your packages into the project, change some configs and now you have all the base functionality you need for your project.

File Structure

In theory the packages for Laravel can have any file structure that you want, but I like to keep this as close to the Laravel structure as I can. The most important file you'll have in your package is the composer.json file, this will tell composer all the information it needs to know about your package. This file will be located at the root of your package. Along with the composer file you should make sure that you include a README.md file this should hold instructions to other developers on how to setup your package and what functionality it will add to Laravel. Next I will have two folders the src folder to store all the code for you package and a tests to store any tests you have for your package. Having this in the same repository as your package means other developers that use your package can easily locate and run your unit tests.

Add Composer.json File

The first file you need in the package is the composer.json file which tells composer the dependencies you need for the package. This is also going to be used for the autoload configurations of the packages, using a PSR-4 settings. The composer.json file should look similar to the below.


{
  "name": "paulund/laravel-package",
  "description": "Laravel Package",
  "require": {

  },
  "require-dev": {
    "phpunit/phpunit": "~7.0"
  },
  "authors": [
    {
      "name": "Paulund",
      "email": "[email protected]"
    }
  ],
  "autoload": {
    "psr-4": {
      "Paulund\\LaravelPackage\\": "src/"
    }
  },
  "scripts": {
    "cs": "php-cs-fixer fix"
  }
}

At the top of the file you put information about the package such as the name and a short description of what the package does. Next you'll use the require or require-dev nodes to enter what dependencies your package will have. For example if you want your package to use guzzle then you can add the following to your composer file.


  "require": {
    "guzzlehttp/guzzle": "^6.2"
  }

Then you have the require-dev node, this will hold dependencies that you only want in your development environment. When you deploy your project you should install the dependencies with composer in no dev mode.


composer install --no-dev

This will only install the dependencies in the require node.

SRC Folder

The next folder you need to add to the package at the root level is the src folder, this is where the code base for the package will live. You can keep this structure however way you want but I like to keep this the same structure as a normal Laravel project as it makes it easier for others to work out where the code will live.

Laravel Auto Package Discovery

In Laravel 5.5 a new feature was released which allowed Laravel to auto discovery the packages installed and add their providers to the app providers. This allows you to add a new node to your composer.json file which will tell Laravel where your service provider is located.


"extra": {
    "laravel": {
        "providers": [
            "Paulund\\LaravelPackageServiceProvider"
        ]
    }
},

Register Your Package

The package service provider is the connection between your package and Laravel. It allows you to take advantages of all the Laravel features and events such as the register and boot function. This will be responsible for binding classes in to the Laravel container and registering any events or facades your package might have. You package service provider must extend Illuminate\Support\ServiceProvider and will contain register method and boot method.

What Can You Use Packages For?

A package can be used to store all reusable functionality you want in a handle package to be imported into any Laravel application. You can use it to publish config files, views, assets, routes, migrate files, translations, commands and also any PHP class can be used from your package.

Config Files

Packages have the ability to publish config files to your Laravel application. These config files will be located inside you package folder and can be used to customise the functionality of your application. To tell Laravel which config files it can publish you can use the method publishes() inside the boot method.


public function boot() {
    // Config file
    $this->publishes([
        __DIR__ . '/Config/package.php' => config_path('package.php')
    ]);
}

When the developer runs the command php artisan vendor:publish, Laravel will search in your package for a file in Config/package.php and copy this file into the Laravel application config folder under a file named package.php. It's worth noting that if the package is updated and you want the latest version of the config file php artisan vendor:publish will not overwrite the file. To overwrite the config files you'll need to add the --force command. If you don't want to create a brand new config and just want to merge your packages config with an existing config then you can use the the mergeConfigFrom method. This will take you configs and do an array merge with the existing config files.


public function boot()
{
    $this->mergeConfigFrom(
        __DIR__.'/path/to/config/blog.php', 'blog'
    );
}

Routes

You can define your own routes in your package and when your package is loaded it will automatically add your routes into your applications routes. For example if you had a package to create an endpoint to send a contact form email, you might have something like.


Route::post('/contact', 'ContactController@store');

Add the following into your Service Provider and the above route will be available to your application.


public function boot()
{
    $this->loadRoutesFrom(__DIR__.'/routes.php');
}

Now if you run the command php artisan route:list it will show you this new route from the package.

Migration Files

If your package needs a new database table setup then you can add Laravel migration files in your package, and register these in your service provider. When you run php artisan migrate Laravel will grab the migration files from your package and run them on your database. To register them in your package use the following method.


public function boot()
{
    $this->loadMigrationsFrom(__DIR__.'/path/to/migrations');
}

Views

You can include blade templates in your packages and bring them into your application to use these views inside your Laravel application. To load views in from your package use the below code.


public function boot()
{
    $this->loadViewsFrom(__DIR__.'/path/to/views', 'blog');
}

The first parameter is the folder of your package views, the second parameter is the namespace you'll use for the views in your package. For example if you have a posts.blade.php inside your views folder then you can use this in a controller by using the following code.


return view('blog::posts');

You can also publish the view which will copy your package views into the Laravel application. This is so you can change the view slightly if you need to and edit the html. To allow you to publish the view files you need to use the publishes() method.


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

When you run php artisan vendor:publish Laravel will copy these view files into the resources/views/vendor/blog.

Commands

Laravel allows you to create code to run on the command line, you can include these in your package by registering them in your service provider.


public function boot()
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            FooCommand::class,
            BarCommand::class,
        ]);
    }
}

Now you'll have these available from artisan which you can see when you run the command php artisan.

Assets

You can also include assets from your package, such as CSS, JavaScript and images. These can be published from your package into your resources/vendor folder. This is important if you're using something like VueJS as your frontend components in your package and you want the application to reuse these components. To allow your package to publish the assets you need to add the following code.


public function boot()
{
    $this->publishes([
        __DIR__.'/path/to/assets' => public_path('vendor/blog'),
    ], 'blogpackage');
}

Code Repository

Now that you understand what can be achieved with your Laravel package it's important to understand how you can build the packages. You can build it in any way you want, you can start off by creating a new folder in your application or it can be in a public repository that you use composer to include or you can even have this on a private repository and use composer to include the code. The way I build my packages is that I start off by adding these to a new folder inside the application and I'll use composer feature of path to include the module as a new local repository.


"repositories": [
    {
        "type": "path",
        "url": "../../packages/my-package"
    }
],

When the package is in a stable enough version to use in multiple projects then I'd move this into a private/public git repository so that I can include this in other projects. To use a package in your own private repositories you can use the composer vcs feature to load from different repositories.


"repositories": [
    {
      "type": "vcs",
      "url":  "[email protected]:username/repo-name.git"
    }
],

Now you can add this repository into your require config. This will allow you to reuse any of the code you build in your Laravel applications. I recommend when you see the chance to move a bit of reusable code into a package you do so...it will make your future projects a lot quicker and easier to work with.