Laravel Package toolkit is a powerful tool designed to streamline the process of creating and managing packages for Laravel. It provides a set of intuitive abstractions and helper methods for common package development tasks, enabling developers to focus on building features rather than boilerplate code.
- Simple and expressive package configuration
- Automatic handling of routes, migrations, translations, and views
- Support for view components
- Built-in exception handling for package-specific errors
- Comprehensive language support
- Install command with customizable publishing options
- Conditional resource loading based on environment
- Lifecycle hooks for advanced customization
- Middleware registration and management
- Laravel 9.x
- Laravel 10.x
- Laravel 11.x
- Laravel 12.x
- Installation
- Usage
- Lifecycle Hooks
- Name
- Short name
- Config
- Routing
- Middlewares
- Migrations
- Translations
- Commands
- Views
- View Components
- View Component Namespaces
- View Composers
- Shared Data
- Assets
- Providers
- Install Command
- About Command
- Publishing
- Testing
- Versioning
- License
You can install the package via composer:
composer require nyoncode/laravel-package-toolkit
To use Laravel Package Builder, create a ServiceProvider for your package that extends
NyonCode\LaravelPackageToolkit\PackageServiceProvider
:
use NyonCode\LaravelPackageToolkit\PackageServiceProvider;
use NyonCode\LaravelPackageToolkit\Packager;
use NyonCode\LaravelPackageToolkit\Contracts\Packable;
class MyAwesomePackageServiceProvider extends PackageServiceProvider implements
Packable
{
public function configure(Packager $packager): void
{
$packager
->name('My Awesome Package')
->hasConfig()
->hasRoutes()
->hasMigrations()
->hasTranslations()
->hasViews();
}
}
For more control over your package configuration, you can use additional methods and specify custom paths:
use NyonCode\LaravelPackageToolkit\PackageServiceProvider;
use NyonCode\LaravelPackageToolkit\Packager;
use NyonCode\LaravelPackageToolkit\Contracts\Packable;
class AdvancedPackageServiceProvider extends PackageServiceProvider implements
Packable
{
public function configure(Packager $packager): void
{
$packager
->name('Advanced package')
->hasShortName('adv-pkg')
->hasConfig('custom-config.php')
->hasRoutes(['api.php', 'web.php'])
->hasMigrations('custom-migrations')
->hasTranslations('lang')
->hasViews('custom-views')
->hasComponents([
'data-table' => DataTable::class,
'modal' => Modal::class,
]);
}
public function registeringPackage(): void
{
// Custom logic before package registration
}
public function bootingPackage(): void
{
// Custom logic before package boot
}
}
You can also use the when()
method to conditionally register resources:
use NyonCode\LaravelPackageToolkit\PackageServiceProvider;
use NyonCode\LaravelPackageToolkit\Packager;
use NyonCode\LaravelPackageToolkit\Contracts\Packable;
class ConditionalPackageServiceProvider extends PackageServiceProvider implements
Packable
{
public function configure(Packager $packager): void
{
$packager
->name('Conditional package')
->hasRoutes(['api.php', 'web.php'])
->hasMigrations('custom-migrations')
->hasTranslations('lang')
->hasViews('custom-views')
->when($this->isInLocal(), function ($packager) {
$packager->hasConfig('local-config.php');
$packager->hasCommands();
})->when($this->isInProduction(), function ($packager) {
$packager->hasConfig('production-config.php');
$packager->hasRoutes('web.php');
});
}
}
Local and production resources will be registered when the isInLocal()
and isInProduction()
methods return true
.
The package provides several convenient methods for conditional loading:
$packager
// Environment-based conditions
->whenEnvironment(['local', 'testing'], function ($packager) {
$packager->hasCommands(['DevCommand::class']);
})
->whenProduction(function ($packager) {
$packager->hasConfig('production-config.php');
})
->whenLocal(function ($packager) {
$packager->hasConfig('local-config.php');
})
// Runtime conditions
->whenConsole(function ($packager) {
$packager->hasCommands();
})
// Class/extension existence
->whenClassExists('SomeClass', function ($packager) {
$packager->hasConfig('optional-config.php');
})
->whenExtensionLoaded('redis', function ($packager) {
$packager->hasConfig('redis-config.php');
});
The package provides lifecycle hooks that allow you to execute custom logic at specific points during package registration and booting:
Hook Method | Description |
---|---|
registeringPackage() |
Called before register() is called |
registeredPackage() |
Called after register() is called |
bootingPackage() |
Called before boot() is called |
bootedPackage() |
Called after boot() is called |
You can define lifecycle hooks directly in your package configuration:
$packager
->name('My Package')
->registeringPackage(function ($packager) {
// Logic executed before package registration
Log::info('Registering My Package');
})
->registeredPackage(function ($packager) {
// Logic executed after package registration
$this->app->singleton('my-service', MyService::class);
})
->bootingPackage(function ($packager) {
// Logic executed before package boot
Event::listen('my-event', MyListener::class);
})
->bootedPackage(function ($packager) {
// Logic executed after package boot
Log::info('My Package fully loaded');
});
Define a name for the package:
$packager->name('Package name');
Define a custom short name for the package.
The hasShortName method is used to modify the name defined by name()
if you prefer not to use the short version from
$packager->name('Package name')
:
$packager->hasShortName('custom-short-name');
The short name must be in kebab-case format and contain only lowercase letters, numbers, and hyphens.
To enable configuration in your package:
$packager->hasConfig();
By default, this will load configuration from the config
directory. For custom config files:
$packager->hasConfig(['config.php', 'other-config.php']);
Or for specific file paths:
$packager->hasConfig([
'../www/config/config.php',
'../api/config/other-config.php',
]);
To use an alternative directory for config files.
$package->hasConfig(directory: 'customConfig');
To enable routing in your package:
$packager->hasRoutes();
By default, this will load routes from the routes
directory. For custom route files:
$packager->hasRoutes(['api.php', 'web.php']);
Or for specific file paths:
$packager->hasRoute(['../www/routes/web.php', '../api/routes/api.php']);
To use an alternative directory for route files.
$package->hasRoute(directory: 'webRouter');
To register middleware for your package, use these methods:
To define route middleware aliases:
$packager->hasMiddlewareAliases([
'custom.alias' => \Vendor\Package\Http\Middleware\CustomMiddleware::class,
'auth.custom' => \Vendor\Package\Http\Middleware\CustomAuthMiddleware::class,
]);
This allows you to assign the middleware to routes using its alias:
Route::get('/example', fn () => 'Hello')->middleware('custom.alias');
To push middleware into existing middleware groups:
$packager->hasMiddlewareGroups([
'web' => [
\Vendor\Package\Http\Middleware\WebMiddleware::class,
],
'api' => [
\Vendor\Package\Http\Middleware\ApiMiddleware::class,
\Vendor\Package\Http\Middleware\RateLimitMiddleware::class,
],
]);
This will automatically add your middleware to the specified groups (e.g. web, api).
To register global middleware (executed for every request):
$packager->hasMiddlewareGlobals([
\Vendor\Package\Http\Middleware\GlobalMiddleware::class,
\Vendor\Package\Http\Middleware\SecurityMiddleware::class,
]);
This middleware will be added to the middleware stack and is useful for applying middleware to all routes regardless of their group.
To enable migrations:
$packager->hasMigrations();
Or for specific file paths:
$packager->hasMigrations([
'../www/database/migrations/2023_01_01_000000_create_users_table.php',
'../api/database/migrations/2023_01_01_000001_create_roles_table.php',
]);
This loads migrations from the database/migrations
directory. For a custom directory:
$packager->hasMigrations(directory: 'custom-migrations');
To use an alternative directory for migration files.
$package->hasMigrations(
['2023_01_01_000000_create_users_table.php'],
'userMigrations'
);
For more information about migrations, see Laravel migrations.
$packager->canLoadMigrations();
This will load migrations directly when the package is registered, without requiring them to be published first.
To enable translations:
$packager->hasTranslations();
This loads translations from the lang
directory and automatically supports JSON translations.
For a custom directory:
$packager->hasTranslations('custom-lang-directory');
The package automatically validates language directory names against supported language codes and detects JSON translation files.
To enable commands:
$packager->hasCommands();
Defaults to loading commands from the Commands
directory.
To use an alternative directory for command files.
$packager->hasCommands(directory: 'custom-commands');
For single command:
$packager->hasCommand('\Vendor\Package\Commands\CustomCommand::class');
Or for specific file names:
$packager->hasCommands([
'\Vendor\Package\Commands\CustomCommand::class',
'\Vendor\Package\Commands\OtherCommand::class',
]);
For more information about commands, see Laravel commands.
To enable views:
$packager->hasViews();
This loads views from the resources/views
directory. For a custom directory:
$packager->hasViews('custom-views');
You can also specify a custom views directory with a different path:
$packager->hasViews(
viewsPath: 'my-views',
directory: '../resources/my-views'
);
To register multiple view components:
$packager->hasComponents(
prefix: 'nyon',
components: [
'data-table' => DataTable::class,
'modal' => Modal::class,
Sidebar::class,
]
);
To register a single view component with an optional alias:
$packager->hasComponent('nyon', Alert::class, 'custom-alert');
You can then use these components in your Blade templates:
<x-nyon-data-table :data="$users"/>
<x-nyon-modal title="User Details">
<!-- Modal content -->
</x-modal>
<x-nyon-sidebar id="sidebar"/>
<x-nyon-custom-alert type="warning" message="This is a warning!"/>
To register multiple view component namespaces:
$packager->hasComponentNamespaces(
namespaces: [
'nyon' => 'App\View\Components\Alert',
'admin' => 'App\View\Components\Modal',
]
);
To register a single view component namespace with an optional alias:
$packager->hasComponentNamespace('nyon', 'App\View\Components\Alert');
You can then use these namespaces in your Blade templates:
<x-nyon::alert :data="$users"/>
<x-admin::modal title="User Details">
<!-- Modal content -->
</x-admin-modal>
To register multiple view composers:
$packager
->hasViewComposer(
views: 'nyon',
composers: fn($view) => $view->with('test', 'test-value')
)->hasViewComposer(
views: ['viewName', 'anotherViewName'],
composers: MyViewComposer::class
);
You can also bind a composer to all views using the wildcard *
:
$packager->hasViewComposer('*', function ($view) {
$view->with('globalData', 'available-everywhere');
});
To add shared data to views:
$packager->hasSharedDataForAllViews(['key' => 'value', 'user' => 'john']);
This adds key-value pairs to the shared data array in the view. The shared data must have string keys and values must be scalar, array, null, or implement the Arrayable
interface.
For more information about shared data, see Laravel shared data.
To enable assets:
$packager->hasAssets();
This loads assets from the dist
directory by default. For a custom directory:
$packager->hasAssets('public');
Assets will be published to public/vendor/{package-short-name}
when using the publish command.
To enable service providers:
$packager->hasProvider('../stubs/MyProvider.stub');
Support for multiple service providers:
$packager->hasProvider('../stubs/MyProvider.stub')
->hasProvider('../stubs/MyOtherProvider.stub');
$packager->hasProviders([
'../stubs/MyProvider.stub',
'../stubs/MyOtherProvider.stub',
]);
Service providers will be published to app/Providers/{ProviderName}.php
when using the publish command.
The package provides a powerful install command system that allows users to easily install and configure your package.
To enable the install command:
$packager->hasInstallCommand();
This creates a command {package-short-name}:install
that users can run to install your package.
You can configure what gets installed using a callback:
$packager->hasInstallCommand(function (InstallCommand $command) {
$command->publishConfig()
->publishMigrations()
->publishAssets()
->publishViews();
});
The install command supports several configuration options:
$packager
// Custom command name
->installCommandName('setup') // Creates package:setup instead of package:install
// Hide command from artisan list
->installCommandHidden(true)
// Auto-install when package loads
->installOnRun(true)
// Install only in specific environments
->installOnRunInEnvironment(['local', 'testing'])
->installOnRunInLocal()
->installOnRunInProduction();
The package provides several pre-built installation configurations:
// Quick install (config, migrations, assets)
$packager->hasQuickInstall();
// Full install (everything)
$packager->hasFullInstall();
// Minimal install (config only)
$packager->hasMinimalInstall();
// Development install (config, migrations, views, assets, routes in local only)
$packager->hasDevInstall();
For more advanced configurations, you can use the full callback approach:
$packager->hasInstallCommand(function (InstallCommand $command) {
$command
->publishConfig()
->publishMigrations()
->publishAssets()
->publishForEnvironment(['local'], 'routes')
->publishForProduction('config')
->beforeInstallation(function ($command) {
$command->info('Starting installation...');
})
->afterInstallation(function ($command) {
$command->info('Installation completed!');
$command->call('migrate');
})
->askToStarRepoOnGitHub('https://github.com/your/repo');
});
The install command supports the following publishing methods:
publishConfig()
/publishConfigFile()
/publishConfigFiles()
publishMigrations()
publishRoutes()
/publishRouteFiles()
publishTranslations()
/publishTranslationFiles()
/publishLanguageFiles()
publishAssets()
/publishPublicAssets()
publishViews()
/publishViewFiles()
publishProviders()
/publishServiceProviders()
publishComponents()
/publishViewComponents()
publishComponentNamespaces()
/publishViewComponentNamespaces()
publishEverything()
/publishAll()
publishEssentials()
(config, migrations, assets)
You can conditionally publish resources:
$command
->publishIf($someCondition, 'config', 'migrations')
->publishUnless($otherCondition, 'routes')
->publishForEnvironment(['local', 'testing'], 'routes')
->publishForProduction('config')
->publishForLocal('assets');
Laravel Package Builder provides methods to add package information to Laravel's php artisan about command.
The hasAbout() method allows you to include your package's information in the Laravel About command. By default, it will include the package's version.
$packager->hasAbout();
The hasVersion() method lets you manually set the version of your package:
$packager->hasVersion('1.0.0');
If no version is manually set, the package will automatically retrieve the version from your composer.json file.
You can extend the about command information by implementing the aboutData()
method in your service provider:
public function aboutData(): array
{
return [
'Repository' => 'https://github.com/your/package',
'Author' => 'Your Name',
'License' => 'MIT',
'Documentation' => 'https://docs.example.com',
];
}
This method allows you to add custom key-value pairs to the About command output for your package.
When you run php artisan about
, your package's information will be displayed in a dedicated section.
This implementation allows for flexible and easy inclusion of package metadata in Laravel's system information command.
For publishing, you can use the following commands:
php artisan vendor:publish
vendor:publish
show all the tags that can be used for publishing.
Each resource type has its own publishing tag in the format {package-short-name}::{resource-type}
:
{package-name}::config
- Configuration files{package-name}::migrations
- Database migrations{package-name}::routes
- Route files{package-name}::translations
- Translation files{package-name}::assets
- Public assets{package-name}::views
- View files{package-name}::providers
- Service providers{package-name}::view-components
- View components{package-name}::view-component-namespaces
- View component namespaces
Use php artisan vendor:publish --tag=package-short-name::config
for publish configuration files.
# Publish specific resources
php artisan vendor:publish --tag=my-package::config
php artisan vendor:publish --tag=my-package::migrations
php artisan vendor:publish --tag=my-package::assets
# Publish with force (overwrite existing files)
php artisan vendor:publish --tag=my-package::config --force
composer test
The package includes comprehensive tests for all features including:
- Configuration loading and publishing
- Route registration
- Middleware registration
- Migration handling
- Translation loading
- View and component registration
- Command registration
- Install command functionality
- Lifecycle hooks
- Conditional loading
This package follows Semantic Versioning (SemVer).
Given a version number MAJOR.MINOR.PATCH
, we increment the:
- MAJOR version when we make incompatible API changes
- MINOR version when we add functionality in a backwards compatible manner
- PATCH version when we make backwards compatible bug fixes
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH
format.
- Major versions may contain breaking changes
- Minor versions will maintain backward compatibility within the same major version
- Patch versions will only contain bug fixes and security updates
We recommend using version constraints in your composer.json
that allow for minor and patch updates but protect against major version changes:
{
"require": {
"nyoncode/laravel-package-toolkit": "^1.0"
}
}
The MIT License (MIT). Please see License File for more information.