ยท yebor974 ยท Advanced Techniques, Tutorials

Building a Laravel Filament Multi-Tenant Panel

Learn how to create a Filament multi-tenant panel with tenant registration, profile management, and customizable tenant menus.

Building a Laravel Filament Multi-Tenant Panel - picture

In modern application development, multi-tenancy is a crucial approach for SaaS solutions or applications shared across multiple entities. With Filament, a powerful administration tool for Laravel, setting up a robust and scalable multi-tenant system becomes straightforward.

In this guide, we will set up a multi-tenancy panel with Filament named Member. The tenant model will be Entity, and it will include a name field.

Security and role-based access will not be covered in this article but will be addressed in another one.

Step 1: Preparing the Entity Model

Start by creating the tenant model Entity. This model will only include a name field for simplicity. To manage users within each tenant, we will leverage the existing User model. We assume that a users table already exists.

php artisan make:model Entity -m

Update the migration file for the entities table:

public function up(): void
{
    Schema::create('entities', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->timestamps();
    });
	
    Schema::create('entity_user', function (Blueprint $table) {
        $table->id();
        $table->unsignedBigInteger('user_id');
        $table->unsignedBigInteger('entity_id');
        $table->timestamps();
    });
}

Update your Entity and User model to add associated relationship:

class Entity extends Model
{
     public function users(): BelongToMany
     {
        return $this->belongsToMany(
            User::class,
            'entity_user')
        )->withTimestamps();
     }
}

class User extends Model
{
     public function entities(): BelongToMany
     {
        return $this->belongsToMany(
            Entity::class,
            'entity_user')
        )->withTimestamps();
     }
}

Run the migration:

php artisan migrate

Step 2: Configure the User model for multi tenancy

We need to define some functions in our User model to implement the FilamentUser, HasTenants, and HasDefaultTenant interfaces:

use Filament\Models\Contracts\FilamentUser;
use Filament\Models\Contracts\HasDefaultTenant;
use Filament\Models\Contracts\HasTenants;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements FilamentUser, HasTenants, HasDefaultTenant 
{
    public function entities(): BelongToMany
    {
        return $this->belongsToMany(
            Entity::class,
            'entity_user')
        )->withTimestamps();
    }

    public function canAccessTenant(Model $tenant): bool
    {
        return $this->entities->contains($tenant);
    }

    public function getTenants(Panel $panel): array|Collection
    {
        return $this->entities ?? [];
    }

    public function getDefaultTenant(Panel $panel): ?Model
    {
        return $this->entities()->first();
    }
}

Step 3: Create a Tenant Registration page

To allow users to register new tenants, we will create a registration page by extending RegisterTenant.

php artisan make:filament-page RegisterTenant

and choose the correct panel id (member for the example).

namespace App\Filament\Member\Pages;

use App\Models\Entity;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\Tenancy\RegisterTenant as BaseRegisterTenant;

class RegisterTenant extends BaseRegisterTenant
{
    public static function getLabel(): string
    {
        return 'Register your company';
    }

    public function form(Form $form): Form
    {
        return $form
            ->schema([
                TextInput::make('name')
                    ->label('Name')
                    ->required()
                    ->maxLength(255),
            ]);
    }

    protected function handleRegistration(array $data): Entity
    {
        /** @var Entity $entity */
        $entity = parent::handleRegistration($data);

        /** @var User $user */
        $user = auth()->user();
        $user->entities()->attach($entity->id);

        return $entity;
    }
}

This page allows users to register a new tenant with a simple name field. When user creates an account, he is automatically redirect to this registration process.

Step 4: Creating the Tenant Entity Profile Page

To allow to edit tenant profile, we will create a profile page by extending EditTenantProfile.

php artisan make:filament-page EditEntityProfile

and choose the correct panel id (member for the example).

namespace App\Filament\Member\Pages;

use App\Models\Entity;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Pages\Tenancy\EditTenantProfile;

class EditTenantProfile extends EditTenantProfile
{
    public static function getLabel(): string
    {
        return 'Edit your company';
    }

    public function form(Form $form): Form
    {
        return $form
            ->schema([
                TextInput::make('name')
                    ->label('Name')
                    ->required(),
            ]);
    }
}

This page allows users to edit their current tenant with a simple name field.

Step 5: Add Tenant to panel

Now, we need to set panel as Tenant:

use App\Filament\Member\Pages\EditTenantProfile;
use App\Filament\Member\Pages\RegisterTenant;
use App\Models\Entity;
use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        ->default()
        ->id('member')
        ->tenant(Entity::class)
        ->tenantRegistration(RegisterTenant::class)
        ->tenantProfile(EditTenantProfile::class)
        ->tenantMenuItems([
            'register' => MenuItem::make()->label('New company'),
        ]),
        //...
}
  • ->tenant(Entity::class) defines the tenant model.
  • ->tenantRegistration(RegisterTenant::class) defines the registration tenant page.
  • ->tenantProfile(EditTenantProfile::class) defines the edit tenant page.
  • ->tenantMenuItems([..]) permits to add menu items on the tenant menu on sidebar.
  • 'register' => MenuItem::make()->label('New company') permits user to add more tenant entities in our config. You dont need to add this line like Edit Tenant Profile page on tenantMenuItems, they are present by default. However, you can customize label here or other criteria like authorization.

Filament Mastery Register Tenant Page

Filament Mastery Tenant Dashboard Example

Filament Mastery Switch Tenant Example

Filament Mastery Edit Tenant Page

Enjoyed this article? Like it or sign up on Filament Master to let me know if you'd like a follow-up on adding role-based security and customizing each tenant's interface with unique logos and colors!

Avatar of yebor974
yebor974
Freelance - French IT Engineer passionate about Laravel and Filament PHP, creating innovative solutions to simplify web development.
React
Share post

Stay ahead in the Filament Mastery adventure

Join our community of Filament PHP enthusiasts! Get exclusive tips, tutorials, and updates delivered straight to your inbox.