Laravel Package Development : Key Steps to Building an Effective Tool

You may have already seen or used Laravel packages such as Sanctum, Passport, Nova and many others. But have you ever wondered how you can package and deploy your development into a package, of any logic, and share it with other developers in the Laravel community?

One of the key features, of the Laravel framework, is the ecosystem of packages, which provide amazing opportunities to build high quality applications.

Packages are the primary way to add any kind of functionality to Laravel projects. This can be anything from a set of styles and scripts to complex business logic and API integrations.

Package code can be standalone or serve as an add-on for a particular framework and can be developed and maintained by different developers.

In this article, we will focus on writing packages for the Laravel framework.

The concept of package development includes concepts like ServiceProvider, Facades, Contracts. All these elements ensure the stable operation of applications from testing to production.

ServiceProvider is the point of contact between the application container and your package. All application resources are managed through it. Dependency injection is the best thing you can think of.

Why Develop and Use Packages in Laravel?

Often developers need to reuse code together or separately from the main application. Extracting some of the code into packages is the best solution. Ease of integration and code reuse is the hallmark of the package ecosystem.

Packages are one of the whales of the framework's popularity, as they contribute to the active development of the Laravel community and are a great way to increase the visibility and appeal of the PHP language and the framework as a whole.

Packages are an integral part of the framework's strong architecture.

Advantages and Disadvantages of using packages

As is usually the case, there is a spoonful of tar in the honey barrel. Package development in Laravel has its own nuances as well.

Pros:

  • scaling projects
  • improve project structure
  • encapsulate business logic
  • promotes code reuse and sharing

Cons:

  • package dependencies may not be to your liking
  • a widely used package may have features you clearly don't need.
  • end of developer support
  • version incompatibility: programming language, dependencies, frameworks

Package Preparation and Development

Creating a proper package structure including directories, configuration files and ServiceProvider classes is also an important part.

All framework dependencies are managed through the package manager composer. Composer has the main role of creating a new package.

Hopefully developers understand the disadvantages of ignoring the package manager.

Basic folder structure within a package

Having a Laravel application, the package directory structure will look like:

├── packages
│   └── coderden
│       └── jwt-auth
│           ├── src

Let's look at each catalog separately:

  • packages is a directory to store all the packages you have created.
  • coderden is the vendor that develops the package/s (e.g. like laravel, spatie). One vendor can have many packages and all of them will be in this directory.
  • jwt-auth - the main directory of the package.
  • src - will contain the source code of our package, as an app directory in the framework. Directories with configuration, migrations and additional logic will also be located at this level.

To start developing a package, first create a packages directory inside an existing Laravel project.

  • Then initialize a new composer.json configuration file in the newly created directory to enter package details such as name, description, type, and other useful information that will describe your package.
mkdir -p packages/coderden/jwt-auth && composer init
Package name (<vendor>/<name>): coderden/jwt-auth
Description []: JWT auth package
Author: Denis Sinyukov <dnsinyukov@gmail.com>
Minimum Stability []: dev
License []: MIT
Would you like to define your dependencies (require) interactively [yes]? no
Would you like to define your dev dependencies (require-dev) interactively [yes]? no
Do you confirm generation [yes]? yes
cd packages/coderden/jwt-auth && mkdir src

After doing all the steps, you have a new composer.json file. This is the cover page for your package.

{
    "name": "coderden/jwt-auth",
    "description": "JWT auth package",
    "type": "library",
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "Coderden\\JwtAuth\\": "src/"
        }
    },
    "authors": [
        {
            "name": "Denis Sinyukov",
            "email": "dnsinyukov@gmail.com"
        }
    ],
    "minimum-stability": "dev",
    "require": {}
}

After initializing the package, we need to inform the application kernel about the new piece of code to be integrated. To do this, we need to create a ServiceProvider. It will be our bridge to deliver resources to the main container.

In the src directory we will create a file JWTServiceProvider.php, the boot() and register() methods will load the package resources and register connections in the IoC container (views, configuration and localization files, migrations, etc).

To test the performance, let's add a test function - dd().

<?php

namespace Coderden\JwtAuth;

use Illuminate\Support\ServiceProvider;

class JWTServiceProvider extends ServiceProvider
{
    public function boot()
    {
        dd('Hello Package!');
    }
}

So, the skeleton of our package is almost written, but the Laravel application still doesn't know the novelty. To do this, we need to tell the package manager to install it and specify the correct namespace.

Let's add the repositories argument to the main file composer.json, the one from Laravel, and run the package installation on the prescribed path.

composer require coderden/jwt-auth:dev-main
"repositories": [
    {
        "url": "packages/coderden/jwt-auth",
        "type": "path"
    }
],

By doing this we have linked the Laravel application and the created package. The repositories option says that there is a new repository at the url path, and composer require - already installs it.

Package discovery

But how do we know that Laravel is using our package? Earlier we said that the entry point to the created package is the JWTServiceProvider. Install installed it, but it's not called anywhere.

There are several ways to do this:

  • The main service provider registration file is config/app.php, where the providers parameter defines the list of service providers to be loaded by laravel and their order. After installing the package, you can write JWTServiceProvider to the providers section.
 'providers' => [
        // TODO Core Service Providers

        /*
         * Package Service Providers...
         */
        \Coderden\JwtAuth\JWTServiceProvider::class,
    ],

By running the composer dump command you will see our greeting text.

"Hello Package!" // packages/coderden/jwt-auth/src/JWTServiceProvider.php:11
  • Recommended method. To automatically add the provider to the call list, you can define the provider in the extra file section of your composer.json package. By running the composer dump command you will see the same result as in the first example.
// packages/coderden/jwt-auth/composer.json

"extra": {
    "laravel": {
        "providers": [
            "Coderden\\JwtAuth\\JWTServiceProvider"
        ]
    }
}

Conclusion

In this article we have considered the reasons, advantages and disadvantages of creating packages for local use, using Laravel packages as an example.

We have created a skeleton for a package that will be filled with logic that the developer wanted to share in the Laravel community or for personal use, tired of duplicating code from project to project.

Creating your own packages is easy enough following all the tips in this article.

In the next articles we will create a package filled with logic and publish it in the Packagist repository.

Related links

Similar Articles