Install the Package
composer require relayercore/laravel-installer
Ensure your project uses Laravel 10–12 and PHP 8.2+.
Publish Configuration
php artisan vendor:publish --tag=installer-config
Edit config/installer.php to set:
pdo, mbstring)storage/app)\App\Models\User)php artisan key:generate).Publish Views (Optional)
php artisan vendor:publish --tag=installer-views
Customize Blade templates in resources/views/vendor/installer/.
Test the Installer
php artisan serve and visit /install.storage/installed is created post-install.Block App Access Until Installed
The package includes middleware to redirect all routes to /install until storage/installed exists. No additional setup is needed.
Middleware-Driven Access Control
InstallerMiddleware checks for storage/installed and redirects unauthenticated users to /install.app()->hasBeenInstalled() in routes to conditionally block access:
Route::middleware(['web', 'installer'])->group(function () {
// Protected routes
});
Step-Based Installation
app/Http/Livewire/Installer/.// app/Providers/InstallerStepsServiceProvider.php
public function registerSteps()
{
$this->app->make(\RelayerCore\Installer\Contracts\InstallerStep::class)
->addStep(new \App\Livewire\Installer\CustomStep());
}
Configuration-Driven Customization
config/installer.php:
'requirements' => [
'php' => '8.2',
'extensions' => ['pdo', 'mbstring', 'gd'], // Add custom extensions
],
'writable_directories' => [
'storage/app/public', // Add custom directories
],
.env-based overrides):
'admin_model' => env('INSTALLER_ADMIN_MODEL', \App\Models\User::class),
Database Integration
// app/Providers/InstallerServiceProvider.php
public function boot()
{
Installer::extend('database', function ($installer) {
return new \App\Services\CustomDatabaseValidator($installer);
});
}
Post-Install Hooks
'after_install' => function () {
\Artisan::call('migrate:fresh --seed');
\Artisan::call('storage:link');
},
.env with a generic APP_KEY (as per security best practices).after_install hook to regenerate the key:
'after_install' => function () {
\Artisan::call('key:generate');
},
// app/Livewire/Installer/AdminStep.php
public function createAdmin()
{
$user = \App\Models\User::create([
'name' => $this->adminName,
'email' => $this->adminEmail,
'password' => bcrypt($this->adminPassword),
'tenant_id' => $this->tenantId, // Custom field
]);
}
// app/Livewire/Installer/CustomStep.php
protected $rules = [
'custom_field' => 'required|string|max:255',
];
Middleware Conflicts
web middleware elsewhere, ensure installer middleware is applied last to avoid redirect loops.app/Http/Kernel.php:
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\App\Http\Middleware\InstallerMiddleware::class, // Move to end
\Illuminate\Session\Middleware\StartSession::class,
],
Database Connection Testing
after_install:
'after_install' => function () {
if (!Schema::hasTable('users')) {
throw new \Exception("Database schema mismatch. Run migrations first.");
}
},
Livewire Script Paths
/livewire/livewire.js?ver=...), which can break the installer’s Alpine.js integration.InstallerMiddleware:
protected function shouldRedirectToInstaller($request)
{
return ! $request->is('livewire/*[hash]*') && ! file_exists(storage_path('installed'));
}
Admin Model Assumptions
name, email, and password fields. Custom models may require overrides.AdminCreator service:
// app/Providers/InstallerServiceProvider.php
public function boot()
{
Installer::extend('admin', function ($installer) {
return new \App\Services\CustomAdminCreator($installer);
});
}
Environment-Specific Requirements
php: 8.2 are hardcoded in config. For multi-environment setups, use:
'requirements' => [
'php' => env('INSTALLER_PHP_VERSION', '8.2'),
],
Installer Stuck on a Step:
storage/logs/laravel.log) for validation errors.protected function mount()
{
\Log::debug('CustomStep mounted', ['data' => $this->data]);
}
Database Connection Errors:
.env has correct credentials before running the installer.php artisan db:show
Middleware Redirect Loops:
storage/installed is not accidentally deleted during development.// app/Http/Middleware/InstallerMiddleware.php
public function handle($request, Closure $next)
{
if (app()->environment('local') && file_exists(storage_path('installed'))) {
return $next($request); // Bypass in local
}
// ... rest of middleware
}
Custom Steps
InstallerStepsServiceProvider:
// app/Livewire/Installer/CustomStep.php
public function mount()
{
$this->step = 'custom';
}
public function render()
{
return view('installer.steps.custom');
}
Override Views
resources/views/vendor/installer/:
php artisan vendor:publish --tag=installer-views
@extends('installer::layouts.app') to inherit base layouts.Modify Validation Logic
Installer facade to add custom validation:
// app/Providers/InstallerServiceProvider.php
public function boot()
{
Installer::extend('validation', function ($installer) {
return new \App\Services\CustomValidator($installer);
});
}
**Post
How can I help you explore Laravel packages today?