Custom Laravel Packages

Creating a custom Laravel package.

Getting Started - autoload your namespace

If you don’t already have a Laravel project up and running from which you would like to develop your package, go ahead and create a fresh install of Laravel so you can build the package there.

The first real step in creating a Laravel package is to pick a namespace. Typically, this will be the camelcase name of a GitHub repository that you intend to use for distributing your package followed by a slash and the name of your package. For instance, our package is residing in the https://github.com/kirschbaum/laravel-spark-pages/ repository, so the camelcase equivalent is Kirschbaum/LaravelSparkPages.

Why bother with picking a namespace first? You’re going to need it for the following reasons:

  1. The namespace in your composer.json file enables your package to be loaded while you’re developing it. You must do this manually because you can’t “compose require” your package yet, which normally would autoload your package for you. In fact, go ahead and include your package manually by adding the line below to your psr–4 block in composer.json:
"autoload": {
    "classmap": [
        "database"
    ],
    "psr-4": {
        "App\\": "app/",
        "Kirschbaum\\LaravelSparkPages\\": "./packages/kirschbaum/laravel-spark-pages/src"
    }
},
  1. You need your namespace to create your directory structure. Go ahead and create a folder starting at the root level so that you will have the equivalent of “packages/kirschbaum/laravel-spark-pages/src” (adjusted for your namespace). The reason why you shouldn’t include your work within an existing package dependency folder (like “vendor”, for instance) is because if you ran composer update, your work might get deleted.
  2. You need to put your namespace at the top of most of the files within your package. For instance, the key file that loads your app is going to be a service provider that needs to have “[namespace]Kirschbaum\LaravelSparkPages;” at the top of it. If your package includes any controllers or models, they’re also going to have to have the same namespace at the top of each of them.
  3. You use your namespace to add your package’s service provider to Laravel’s “providers” array in the app/config.php file. (see below for more on this.) Go ahead and pick a name for your service provider and put it in that array. It will look something like this (adjusted for your namespace):
Kirschbaum\LaravelSparkPages\PagesServiceProvider::class,

Create a service provider file in your package

Now you can create the file you named above. It needs to be placed in your packages/kirschbaum/laravel-spark-pages/src folder (adjusted for your namespace), and you will also need to create a routes.php file for that folder as well. Go ahead and do that now. The service provider needs to be structured like so:

<?php
namespace Kirschbaum\LaravelSparkPages;

use Illuminate\Support\ServiceProvider;
class PackageServiceProvider extends ServiceProvider
{
    public function boot()
    {
    }

    public function register()
    {
    }
}

Note you should replace “PackageServiceProvider” with a more relevant name for your app. Run “composer dump” so your changes to composer.json will take effect and this class will be recognized by Laravel.

Your routes.php file along with any views, controllers, or models your package will need to be registered in, fittingly, the register() method. You can do that like so:

include __DIR__.'/routes.php';
$this->app->make('Kirschbaum\LaravelSparkPages\PageController');
$this->app->make('Kirschbaum\LaravelSparkPages\Page');
$this->loadViewsFrom(__DIR__.'/../views', 'laravel-spark-pages');

Notice for the last file, you are planning to load your package’s views from your main Laravel app in a folder named after your namespace that doesn’t exist yet (laravel-spark-pages). We’ll cover that in the below section “Copy migrations and customizable files to the Laravel app.”

Create a composer.json file in your package

It needs to be placed in your “packages/kirschbaum/laravel-spark-pages/” folder (adjusted for your namespace) and can follow this general structure:

{
    "name": "kirschbaum/laravel-spark-pages",
    "description": "Easy CMS-like page creation and editing for Laravel Spark",
    "type": "library",
    "license": "MIT",
    "authors": [
        {
            "name": "Bryan Miller",
            "email": "bryan@kirschbaumdevelopment.com"
        },
        {
            "name": "Nathan Kirschbaum",
            "email": "nathan@nathankirschbaum.com"
        }
    ],
    "keywords": ["laravel-spark", "content-management", "pages"],
    "require": {},
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Kirschbaum\\LaravelSparkPages\\": "src/"
        }
    }
}

Some of the above lines are optional, but the key line to include (adjusted for your namespace) is

"Kirschbaum\\LaravelSparkPages\\": "src/"

Add the folders you’ll need

At this point, you can start to think of your package a little bit like a mini-Laravel app in terms of structure and how you’re going to add functionality. Put your Controllers, Models, and routes.php file into the “/src” folder alongside your service provider. Note that any routes you define in your routes.php folder will have to include the whole path of your package’s namespace when referencing controllers, such as this:

Route::get('/pages/{slug}/edit', '\Kirschbaum\LaravelSparkPages\PageController@edit');

Add a few more sibling folders if you know you will need them to be sibling folders to your “/src” folder, such as “database”, “views”, “css”, and “js” folders. In your database folder, you can add a migrations folder along with any migrations you might need. In your views folder, you can add blade files to your package’s controller and routes will need. If you have any JS files, put them in there, etc.

Copy migrations and customizable files to the Laravel app

You will have to publish any migrations you include in your package to the main Laravel app so they’ll get picked up when php artisan migrate gets run. You can do this by including the below block of code in your package’s service provider’s boot() method:

$this->publishes([
    __DIR__.'/../database/migrations/' => database_path('migrations')
], 'migrations');

and then by running the below command from the terminal (adjusted for your namespace):

php artisan vendor:publish --provider="Kirschbaum\LaravelSparkPages\PagesServiceProvider" --tag='migrations'

Note you will still have to run “php artisan migrate” for the migration to run.

If there are any files in your package that users will likely want to customize, such as Blade, CSS or JS files, then include php artisan publish commands so that these files can be referenced outside of your package. This way, if users ever want to update your package, all of their customized changes won’t get deleted. You can do this by adding the below block to the same boot() method as mentioned above:

$this->publishes([
    __DIR__.'/../views/' => base_path('resources/views/vendor/laravel-spark-pages'),
    __DIR__.'/../js/' => base_path('resources/assets/js/vendor/laravel-spark-pages')
], 'assets');

and then by running the below command from the terminal (adjusted for your namespace):

php artisan vendor:publish --provider="Kirschbaum\LaravelSparkPages\PagesServiceProvider" --tag='assets'

And you’re ready to go!

Tags: Laravel, Composer

Interested in speaking with a developer?

Connect with us.
©2020 Kirschbaum Development Group LLC