Creare un progetto Laravel multi-tenant + Filament
Per prima cosa creo il progetto Laravel vaniglia:
# composer create-project laravel/laravel myapp
# mv myapp/* .
# mv myapp/* .
# mv myapp/.env .
# rm-Rf myapp
Poi passiamo a FilamentPHP:
# composer require filament/filament -W
# php artisan filament:install
# php artisan filament:install --panels
Poi creiamo il primo utente amministratore:
# php artisan migrate
# php artisan make:filament-user
Adesso possiamo passare al multi-tenant:
# composer require "spatie/laravel-multitenancy:^4.0"
E pubblichiamo i file necessari:
# php artisan vendor:publish --provider="Spatie\Multitenancy\MultitenancyServiceProvider" --tag="multitenancy-config"
Per proteggere le aree riservate dei vari tenant creiamo un nuovo gruppo Middleware e applichiamolo alle rotte che devono essere protette:
// in `bootstrap/app.php`
return Application::configure(basePath: dirname(__DIR__))
// ...
->withMiddleware(function (Middleware $middleware) {
$middleware
->group('tenant', [
\Spatie\Multitenancy\Http\Middleware\NeedsTenant::class,
\Spatie\Multitenancy\Http\Middleware\EnsureValidTenantSession::class,
]);
});
Poi aggiungiamolo alle rotte nel file dentro la cartella routes:
// in un routes file come web.php
Route::middleware('tenant')->group(function() {
// routes
});
Database multiplo, uno per ogni tenant
Questa impostazione presume che si abbiano 2 tipi di connessione al database:
- landlord: la connessione al database principale che contiene la tabella dei tenants e le altre tabelle del sistema
- tenant: la connessione al database “proprietà” del tenant
In config/database.php:
'tenant' => [
'driver' => 'mysql',
'database' => null,
'host' => '127.0.0.1',
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
// And other options if needed ...
],
'landlord' => [
'driver' => 'mysql',
'database' => env('DB_DATABASE', 'laravel'),
'host' => '127.0.0.1',
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
// And other options if needed ...
],
Adesso pubblichiamo le migrations:
# php artisan vendor:publish --provider="Spatie\Multitenancy\MultitenancyServiceProvider" --tag="multitenancy-migrations"
Questo comando crea una cartella sotto database/migrations chiamata landlord al cui interno vanno messe le migrations specifiche dei tenant che andremo a creare.
# php artisan migrate --path=database/migrations/landlord --database=landlord
Una volta che vogliamo eseguirle per creare le varie tabelle dei tenant, dobbiamo eseguire:
# php artisan tenants:artisan "migrate --path=database/migrations/tenant --database=tenant"
Switchiamo il database specifico del tenant quando accede alla sua area
Ogni volta che un tenant viene indicato come current, il package eseguirà i tasks definiti alla voce switch_tenant_tasks nel file config/multitenancy.php
/*
* These tasks will be performed to make a tenant current.
*
* A valid task is any class that implements Spatie\Multitenancy\Tasks\SwitchTenantTask
*/
'switch_tenant_tasks' => [
Spatie\Multitenancy\Tasks\SwitchTenantDatabaseTask::class,
],
La creazione dei database dei singoli tenant non è gestita in automatico dal pacchetto. Io preferisco crearlo nel momento in cui si crea un nuovo tenant ed il modo per farlo è creando un Observer di questo evento, ma prima creiamo un Model Tenant a cui attaccarlo:
# php artisan make:model Tenant -m
# php artisan make:observer TenantObserver --model=Tenant