TL;DR: How to set up a local development environment to test your package classes or utilities within a local Laravel project.
A sample Laravel project can be found on this Github Repository.
Find out more on Capsules or X.
It shouldn't surprise you to learn that we use hundreds of packages during web tool development. To acquire them, you simply need visit a package manager like Packagist, which had 382,000 of them in October 2023.
If you want to develop your own package, it's entirely reasonable to wonder how to test it under real conditions. Publishing the package on Packagist during development is not an option. Another approach would be to integrate it into a fresh project without using Composer. The method in this article closely simulates a real-world scenario but does require some environment setup.
Create a folder that will serve as the foundation for your package.
mkdir package
Create a composer.json file, which forms the essential foundation of the package.
package/composer.json
{
"name": "capsulescodes/package",
"description": "Capsules Codes Package",
"type": "library",
"autoload": { "psr-4" : { "CapsulesCodes\\Package\\" : "src/" } }
}
-
name: The name should be structured with the entity on the left and the package name on the right. It is highly recommended to use a descriptive package name to facilitate user searches. -
description: The package description should be clear and concise. -
type: There are 4 types:library,project, -metapackage, andcomposer-plugin. Thelibrarytype is the most commonly used.Projectrepresents a project, such as a framework template. -
autoload: This is the core element of our package, defining a namespace to access data located at the root of the project. The class autoloading specification protocol is defined byPSR-4. This is a crucial step. Make sure to include the\\, especially at the end of the statement.
It is advisable to ensure that the name information matches the namespace. Additionally, it is recommended to use src as the folder name at the root of the project.
Furthermore, if you run composer init in a folder that does not contain a composer.json file, a wizard will guide you through the process of creating your composer.json file.
Create a folder src inside the package folder.
cd package
mkdir src
- The arrangement of the files is not really important, except for their proximity, both for you and for this article.
Create a PHP class named Greeter containing a function greet that returns the phrase Hello world!.
package/src/Greeter.php
<?php
namespace CapsulesCodes\Package;
class Greeter
{
public function greet() : string
{
return "Hello world!";
}
}
- Do not forget to indicate the
namespace. Otherwise, the class will not be found.
It is now possible to test this package. To do this, you need to create a testing environment using a Laravel template project.
Return to the parent directory of the package and create a template Laravel project serving as a test.
cd ../../
composer create-project laravel/laravel template
- The
composer create-project laravel/laravel templatecommand generates a'type': 'project'here.
To inform the template that our package is located in the same parent folder, it is necessary to add two pieces of information to the composer.json file.
template/composer.json
...
"minimum-stability": "dev",
"repositories": [ { "type" : "path", "url" : "../package" } ]
...
-
minimum-stability: This option allows the installation of the package viacomposerwithout generating an exception. This is necessary when the package is notstable, in this case, our package is currentlydev. -
repositories: This array allows adding paths to other directories thatcomposershould refer to in order to find a package locally. -
type: The type of directory can becomposer,package, -vcs, orpath. Thepathoption allows for the local use of a package, while thevcsoption allows the use of a package through a version control system such as Github.
It is time to install our new package.
composer require capsulescodes/package
It is now listed in the require dependencies.
package/composer.json
"require": {
...
"capsulescodes/package": "dev-main",
...
}
- Since the package is still in development, the
dev-mainversion is used.
Test via php artisan tinker
php artisan tinker
> CapsulesCodes\Package\Greeter::greet()
= "Hello world!"
You can modify the web.php file to test the Greeter static class.
package/routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use CapsulesCodes\Package\Greeter;
Route::get( '/', fn() => dd( Greeter::greet() ) );
"Hello world!" // routes/web.php:7`
The work environment is ready.
It would be interesting to add the additional method say() to test the tool in real time.
package/src/Greeter.php
<?php
namespace CapsulesCodes\Package;
class Greeter
{
public static function greet() : string
{
return "Hello world!";
}
public static function say( string $something ) : string
{
return $something;
}
}
Test using php artisan tinker. You should probably reload it.
php artisan tinker
> CapsulesCodes\Package\Greeter::say( "That's a quick way to develop and test a package!" )
= "That's a quick way to develop and test a package!"
You can modify the web.php file to test the Greeter static class.
package/routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use CapsulesCodes\Package\Greeter;
Route::get( '/', fn() => dd( Greeter::say( "That's a quick way to develop and test a package!" ) ) );
"That's a quick way to develop and test a package!" // routes/web.php:7
At this stage, everything is ready to develop a PHP Framework-agnostic package. Additional steps are required to create a Laravel package. For this article, the goal is to implement a php artisan greet command that will call the Greeter static class.
It is recommended to follow the typical project structure of Laravel when creating a Laravel package. This makes it easier for those who need it to find information.
First, it is necessary to create the GreetCommand by extending the Illuminate\Console\Command command specific to Laravel.
package/src/Commands/GreetCommand.php
<?php
namespace CapsulesCodes\Package\Console\Commands;
use Illuminate\Console\Command;
use CapsulesCodes\Package\Greeter;
class GreetCommand extends Command
{
protected $signature = "greet";
protected $description = "Greet people with a 'Hello world!'";
public function handle()
{
dump( Greeter::greet() );
}
}
- The base
Illuminate\Console\Commandclass of Laravel is used as an extension. - The previously created static class
Greeteris used in thehandle()method. However, to test the package, you can simply replacereturn Greeter::greet()withreturn "Hello world!".
In order for the model project to recognize this command, it is necessary to notify it using a ServiceProvider.
package/src/Providers/PackageServiceProvider
<?php
namespace CapsulesCodes\Package\Providers;
use Illuminate\Support\ServiceProvider;
use CapsulesCodes\Package\Console\Commands\GreetCommand;
class PackageServiceProvider extends ServiceProvider
{
public function boot()
{
$this->commands( [ GreetCommand::class ] );
}
}
- The base
Illuminate\Support\ServiceProviderclass of Laravel is used as an extension. - The newly created
GreetCommandcommand is added to the array requested by thethis->commandsmethod, allowing thetemplateproject to access the command.
The package must now inform the model project that a new ServiceProvider is available for discovery. This avoids the need to manually add it to the list of ServiceProviders in the template app.php configuration file.
package/composer.json
"extra" : { "laravel" : { "providers" : [ "CapsulesCodes\\Package\\Providers\\PackageServiceProvider" ] } },
Test the php artisan greet command.
php artisan greet
"Hello world!" // ../package/src/Console/Commands/GreetCommand.php:17
If you encounter any issues, it is recommended to execute the composer update command to reload the new package.
You can modify the web.php file to test the greet command via Artisan.
package/routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Artisan;
Route::get( '/', fn() => Artisan::call( 'greet' ) );
"Hello world!" // ../package/src/Console/Commands/GreetCommand.php:17
And if you want to make your GreetCommand available only in console mode, add this condition to the PackageServiceProvider.
package/src/Providers/PackageServiceProvider.php
public function boot()
{
if( $this->app->runningInConsole() ) $this->commands( [ GreetCommand::class ] );
}
It is also possible to implement a config file, migrations, tests, routes, or views. Perhaps, that's something to consider later.
Glad this helped.
Top comments (0)