muhammad-nawlo / multitenant-plugin
A comprehensive multitenant plugin for Filament that integrates seamlessly with stancl/tenancy and filament-shield for role-based permissions
Fund package maintenance!
Muhammad-Nawlo
Requires
- php: ^8.0
- bezhansalleh/filament-shield: ^3.0
- filament/filament: ^3.0
- spatie/laravel-package-tools: ^1.15.0
- stancl/tenancy: ^3.7
Requires (Dev)
- laravel/pint: ^1.0
- nunomaduro/collision: ^7.9
- nunomaduro/larastan: ^2.0.1
- orchestra/testbench: ^8.0
- pestphp/pest: ^2.1
- pestphp/pest-plugin-arch: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
- spatie/laravel-ray: ^1.26
README
A comprehensive multitenant plugin for Filament that integrates seamlessly with stancl/tenancy
and filament-shield
to make multitenant applications easier to build and manage. This plugin provides complete tenant management with role-based permissions and beautiful Filament interfaces.
Features
- 🏢 Tenant Management: Complete CRUD operations for tenants through Filament
- 📊 Tenant Dashboard: Beautiful dashboard with tenant statistics and quick actions
- 🔧 Easy Integration: Simple traits to make your resources tenant-aware
- 🛡️ Shield Integration: Role-based permissions with tenant-specific access control
- ⚙️ Flexible Configuration: Extensive configuration options
- 🚀 Quick Setup: Automated setup command for fast deployment
- 🎨 Modern UI: Beautiful Filament interface for tenant management
- 🔒 Robust Error Handling: Graceful degradation when tenancy isn't available
- 📝 Comprehensive Documentation: Detailed examples and usage guides
- 🛠️ Production Ready: Thoroughly tested with proper error handling and edge cases covered
Installation
- Install the package via Composer:
composer require muhammad-nawlo/multitenant-plugin
- Install required dependencies (if not already installed):
# Install tenancy package composer require stancl/tenancy # Install shield package (optional, for permissions) composer require bezhanSalleh/filament-shield
- Publish the configuration:
php artisan vendor:publish --tag="multitenant-plugin-config"
- Run the setup command:
php artisan multitenant:setup
- Add the plugin to your Filament panel:
use MuhammadNawlo\MultitenantPlugin\MultitenantPluginPlugin; // In your panel configuration $panel->plugins([ MultitenantPluginPlugin::make(), ]);
Quick Start
Making Resources Tenant-Aware
Use the TenantAwareResource
trait in your Filament resources:
<?php namespace App\Filament\Resources; use Filament\Resources\Resource; use MuhammadNawlo\MultitenantPlugin\Traits\TenantAwareResource; class PostResource extends Resource { use TenantAwareResource; // Your resource configuration... }
Making Resources Tenant-Aware with Shield Permissions
Use the TenantAwareShieldResource
trait for resources that need both tenancy and permissions:
<?php namespace App\Filament\Resources; use Filament\Resources\Resource; use MuhammadNawlo\MultitenantPlugin\Traits\TenantAwareShieldResource; class PostResource extends Resource { use TenantAwareShieldResource; // Your resource configuration... // This will automatically check tenant-specific permissions // and scope data to the current tenant }
Making Pages Tenant-Aware
Use the TenantAwarePage
trait in your Filament pages:
<?php namespace App\Filament\Pages; use Filament\Pages\Page; use MuhammadNawlo\MultitenantPlugin\Traits\TenantAwarePage; class Dashboard extends Page { use TenantAwarePage; // Your page configuration... }
Making Pages Tenant-Aware with Shield Permissions
Use the TenantAwareShieldPage
trait for pages that need both tenancy and permissions:
<?php namespace App\Filament\Pages; use Filament\Pages\Page; use MuhammadNawlo\MultitenantPlugin\Traits\TenantAwareShieldPage; class Dashboard extends Page { use TenantAwareShieldPage; // Your page configuration... // This will automatically check tenant-specific permissions // and provide tenant context information }
Making Models Tenant-Aware
Add the BelongsToTenant
trait to your models:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Stancl\Tenancy\Database\Concerns\BelongsToTenant; class Post extends Model { use BelongsToTenant; // Your model configuration... }
Configuration
The plugin provides extensive configuration options in config/multitenant-plugin.php
:
return [ // Tenant model class 'tenant_model' => \Stancl\Tenancy\Database\Models\Tenant::class, // Navigation group for tenant resources 'navigation_group' => 'Tenant Management', // Enable/disable features 'enable_dashboard' => true, 'enable_tenant_resource' => true, // Auto-scope resources to current tenant 'auto_scope_resources' => true, // Middleware configuration 'tenant_middleware' => ['web', 'auth', 'tenant'], 'central_middleware' => ['web', 'auth'], ];
Usage
Tenant Management
The plugin provides a complete tenant management interface:
- List Tenants: View all tenants with search and filtering
- Create Tenant: Add new tenants with custom data
- Edit Tenant: Modify tenant information
- Delete Tenant: Remove tenants safely
- Switch Tenant: Switch between tenant contexts
Tenant Dashboard
Access the tenant dashboard to see:
- Current tenant information
- Tenant statistics (total, active, recent)
- Quick actions for tenant management
- Navigation to tenant resources
API Methods
The traits provide several useful methods:
// Get current tenant $tenant = $this->getCurrentTenant(); // Get tenant ID $tenantId = $this->getTenantId(); // Check if in tenant context $isTenantContext = $this->isTenantContext(); // Scope query to current tenant $query = $this->scopeToTenant($query);
Commands
Setup Command
php artisan multitenant:setup
This command will:
- Publish tenancy configuration
- Publish and run migrations
- Create tenant model
- Update User model to be tenant-aware
- Create tenant middleware
Generate Tenant Permissions
# Generate permissions for a specific tenant php artisan multitenant:generate-permissions tenant-1 # Generate permissions for all tenants php artisan multitenant:generate-permissions --all # Generate permissions and assign to a role php artisan multitenant:generate-permissions tenant-1 --role=tenant_admin
This command will:
- Create tenant-specific permissions for all existing permissions
- Optionally assign permissions to specified roles
- Support bulk generation for all tenants
- Create tenant-specific permission names (e.g.,
view_any_post_tenant-1
)
Force Setup
php artisan multitenant:setup --force
Force setup even if tenancy is already configured.
Middleware
The plugin includes middleware for tenant initialization:
// In your routes Route::middleware(['web', 'auth', 'tenant'])->group(function () { // Tenant-specific routes }); Route::middleware(['web', 'auth'])->group(function () { // Central administration routes });
Advanced Usage
Custom Tenant Identification
You can customize how tenants are identified by modifying the middleware:
// In stubs/EnsureValidTenantSession.php.stub // Choose your preferred method: // Domain-based return app(InitializeTenancyByDomain::class)->handle($request, $next); // Subdomain-based return app(InitializeTenancyBySubdomain::class)->handle($request, $next); // Path-based return app(InitializeTenancyByPath::class)->handle($request, $next);
Error Handling
The plugin is designed to be robust and handle cases where dependencies aren't available:
- Tenancy not available: Plugin works without tenant-specific features
- Shield not available: Plugin works without permission features
- Graceful degradation: Features are disabled rather than causing errors
- Test environment support: Plugin works in testing contexts with proper null checks
- Asset registration: Removed problematic asset registration that caused composer require errors
Custom Tenant Data
Store additional tenant data in the data
column:
$tenant = Tenant::create([ 'id' => 'tenant-1', 'name' => 'My Tenant', 'domain' => 'tenant1.example.com', 'data' => [ 'plan' => 'premium', 'settings' => [ 'theme' => 'dark', 'features' => ['feature1', 'feature2'], ], ], ]);
Tenant-Specific Permissions
The plugin automatically creates tenant-specific permissions. For example:
// Global permission 'view_any_post' // Tenant-specific permission 'view_any_post_tenant-1' 'view_any_post_tenant-2'
This allows you to control access per tenant:
// Check if user can view posts in current tenant if (auth()->user()->can('view_any_post_' . $tenant->getTenantKey())) { // User has permission for this specific tenant }
Using the Permission Service
use MuhammadNawlo\MultitenantPlugin\Services\TenantPermissionService; $permissionService = app('tenant-permission-service'); // Check permission for current tenant if ($permissionService->hasPermission('view_any_post')) { // User has permission } // Get tenant-specific permission name $permissionName = $permissionService->getTenantPermission('view_any_post'); // Returns: 'view_any_post_tenant-1' (if in tenant context)
Testing
composer test
Troubleshooting
Common Issues
-
"Target class [Stancl\Tenancy\TenancyManager] does not exist"
- Make sure you have installed
stancl/tenancy
- Run
composer require stancl/tenancy
- Follow the tenancy package setup instructions
- The plugin will work without tenancy, but tenant-specific features will be disabled
- Make sure you have installed
-
Setup command fails
- Ensure you have write permissions to your app directory
- Check that the User model exists and is writable
- Run
php artisan multitenant:setup --force
to overwrite existing files - The command will create missing directories automatically
-
Permissions not working
- Ensure
filament-shield
is properly installed and configured - Run
php artisan shield:generate
to generate base permissions - Then run
php artisan multitenant:generate-permissions --all
- Check that your User model has the
HasRoles
trait
- Ensure
-
"Class not found" errors in TenantResource
- This usually happens when page namespaces are incorrect
- The plugin now uses fully qualified namespaces to avoid this issue
- If you encounter this, try running the setup command again
-
Syntax errors in User.php after setup
- The setup command now uses regex to properly insert the trait
- If you encounter syntax errors, check the User model file
- Run
php artisan multitenant:setup --force
to fix the User model
-
Plugin not working in test environment
- This is expected behavior as the plugin requires a proper Laravel application
- The plugin includes null checks and try-catch blocks for test environments
- Features will be gracefully disabled in test contexts
Debugging
To debug issues with the plugin:
# Check if tenancy is properly installed php artisan tinker >>> app('Stancl\Tenancy\TenancyManager') # Check if shield is properly installed php artisan tinker >>> app('BezhanSalleh\FilamentShield\FilamentShield') # Verify plugin registration php artisan config:clear php artisan route:clear php artisan view:clear
Getting Help
If you're still experiencing issues:
- Check the stancl/tenancy documentation
- Check the filament-shield documentation
- Open an issue on the GitHub repository with detailed error messages
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.