Getting started on Laravel package development

The package related documentation for Laravel covers the basics on how to include Laravel spesific assets in your package but it does not really provide information on how to get started. So maybe you have noticed a common functionality in separate Laravel projects that could be shared between them. I thought this short tutorial might be useful and hopefully encourages people to create and share useful packages with others. So let’s get started.

Assumptions & prequisites

This is not a beginner level tutorial so I assume you are already familiar with Laravel and feel comfortable using composer and git. We will be creating an awesome package that allows us to multiply two numbers together. Naturally this is just for educational purposes. During this tutorial, the composer package name is lasselehtinen/mypackage and the namespace is lasselehtinen\MyPackage. You can find the completed tutorial in GitHub.


Initiliazing your package

We will start off by creating a new folder and setting up the initial composer.json.

mkdir mypackage
cd mypackage
composer init

The composer config generator will then ask you a bunch of questions. Most of them are self explanatory but for example choosing the license might be tricky if you are not familiar with Open Source licenses and standards. Fortunately there is a helpful web site that helps you make this decision. You can always update these in the composer.json later.

Add PSR-4 autoloading for your package

After you have initiliazed the composer.json you have to add your namespace to the composers autoload section. Basically it binds together the namespace and the relative path in the packages folder.

{
"name": "lasselehtinen/mypackage",
"description": "My awesome Laravel package",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Lasse Lehtinen",
"email": "lasse.lehtinen@foobar.com"
}
],
"require": {},
"autoload": {
"psr-4": {
"lasselehtinen\\MyPackage\\": "src"
}
},

}

Create new service provider

As the official documentation states the packages service provider connects your package with Laravel and defines the assets it provides. Your package might include custom migrations, routes or views. All those are defined in the service provider.

Service providers are the connection points between your package and Laravel. A service provider is responsible for binding things into Laravel’s service container and informing Laravel where to load package resources such as views, configuration, and localization files.

So start creating a new service provider in the packages src directory. Please note the registering of the singleton and creating the alias for the facade that is created on the later stage.

<?php
namespace lasselehtinen\MyPackage;
use Illuminate\Support\ServiceProvider;
class MyPackageServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
    }
    /**
* Register the application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(MyPackage::class, function () {
return new MyPackage();
});
        $this->app->alias(MyPackage::class, 'my-package');
}
}

Create new package class

Since this is a very simple package only containing one method for multiplying, we will have only one single class. So create this class in your src directory.

<?php
namespace lasselehtinen\MyPackage;
class MyPackage
{
/**
* Multiplies the two given numbers
* @param int $a
* @param int $b
* @return int
*/
public function multiply($a, $b)
{
return $a * $b;
}
}

Create a facade

The facade clues the service class and the alias together. So use the same return value for the alias as in the service provider.

<?php
namespace lasselehtinen\MyPackage;
use Illuminate\Support\Facades\Facade;
class MyPackageFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'my-package';
}
}

Testing your package

We wouldn’t want to release anything that is not covered with tests wouldn’t we? So let’s include phpunit and orchestra/testbench for our package. orchestra/testbench is an awesome package that helps testing Laravel spesific packages. Basically it launches a full Laravel application so you can test that your package works correctly with Laravel. Our simple package would go fine with just with phpunit, but I included orchestra/testbench since it is very useful if you provide routes or views in your package. In the example below, we are just testing the service provider and alias.

composer require --dev phpunit/phpunit
composer require --dev orchestra/testbench

Add namespaces for your tests in composer.json

"autoload-dev": {
"psr-4": {
"lasselehtinen\\MyPackage\\Test\\": "tests/"
}
}

Create phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
verbose="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false">
<testsuites>
<testsuite name="MyPackage Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/</directory>
</whitelist>
</filter>
</phpunit>

Create base testcase in tests\TestCase.php. The getPackageProviders and getPackageAliases methods are equivalent of adding your service provider and alias to your Laravel applications config/app.php. So now the test case is creating a Laravel application that has the service provider and alias loaded.

<?php
namespace lasselehtinen\MyPackage\Test;
use lasselehtinen\MyPackage\MyPackageFacade;
use lasselehtinen\MyPackage\MyPackageServiceProvider;
use Orchestra\Testbench\TestCase as OrchestraTestCase;
class TestCase extends OrchestraTestCase
{
/**
* Load package service provider
* @param \Illuminate\Foundation\Application $app
* @return lasselehtinen\MyPackage\MyPackageServiceProvider
*/
protected function getPackageProviders($app)
{
return [MyPackageServiceProvider::class];
}
    /**
* Load package alias
* @param \Illuminate\Foundation\Application $app
* @return array
*/
protected function getPackageAliases($app)
{
return [
'MyPackage' => MyPackageFacade::class,
];
}
}

Create the actual test.

<?php
namespace lasselehtinen\MyPackage\Test;
use MyPackage;
class MyPackageFunctionTest extends TestCase
{
/**
* Check that the multiply method returns correct result
* @return void
*/
public function testMultiplyReturnsCorrectValue()
{
$this->assertSame(MyPackage::multiply(4, 4), 16);
$this->assertSame(MyPackage::multiply(2, 9), 18);
}
}

Then run vendor/bin/phpunit and the tests should have passed.

But my package needs to provide views/routes/commands/migrations!

In case your package needs additional assets that need to be published, I suggest you turn to the official documentation. Those are covered pretty well.

But I want to develop my package in a Laravel application!

In case using TDD with orchestra/testbench does not feel natural for you, fortunately you can use of the composers repository features to link your local package to an existing Laravel application. Just add the package repository as “path” in the Laravel applications composer.json and require your package with the version “dev-master”. Then run composer update, which symlinks the package folder in your vendor directory. Then soon as you have made changes in the package, they are reflected in the Laravel application.

{
"name": "laravel/laravel",
"description": "The Laravel Framework.",
"keywords": ["framework", "laravel"],
"license": "MIT",
"type": "project",
"repositories": [
{
"type": "path",
"url": "../mypackage",
"options": {
"symlink": true
}
}
],

"require": {
"php": ">=5.6.4",
"laravel/framework": "5.4.*",
"laravel/tinker": "~1.0",
"lasselehtinen/mypackage": "dev-master"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*",
"phpunit/phpunit": "~5.7"
},