Installation:
composer require rinvex/laravel-tenants
php artisan rinvex:publish:tenants
php artisan rinvex:migrate:tenants
config/tenants.php to define your tenant model (default: Rinvex\Tenants\Models\Tenant) and tenant identifier (e.g., domain or uuid).First Use Case: Tenant Identification
// app/Http/Kernel.php
'identify-tenant' => \Rinvex\Tenants\Http\Middleware\IdentifyTenant::class,
$middlewareGroups['web'] or create a custom group.Quick Test:
$tenant = \App\Models\Tenant::create(['domain' => 'tenant1.example.com']);
tenant1.example.com in your browser to verify tenant isolation.Tenant Isolation:
use Rinvex\Tenants\Traits\HasTenants;
class User extends Model
{
use HasTenants;
}
HasTenants trait or tenant() method:
class Project extends Model
{
public function tenant()
{
return $this->belongsTo(Tenant::class);
}
}
Middleware Integration:
// Override tenant identification logic
public function handle($request, Closure $next)
{
$tenant = Tenant::where('domain', $request->getHost())->first();
if ($tenant) {
Tenant::setCurrentTenant($tenant);
}
return $next($request);
}
APIs and Tenant Context:
$currentTenant = Tenant::currentTenant();
return response()->json(['tenant_id' => $currentTenant->id]);
Seeding and Testing:
Tenant::setCurrentTenant() in tests or seeders:
Tenant::setCurrentTenant($tenant);
User::factory()->create();
Laravel Scout:
HasTenants for search isolation:
use Rinvex\Tenants\Traits\HasTenants;
use Laravel\Scout\Searchable;
class Product extends Model
{
use HasTenants, Searchable;
}
Queues and Jobs:
public function handle()
{
$tenant = Tenant::currentTenant();
// Job logic...
}
Caching:
Cache::tags(['tenant:' . $tenant->id])->put('key', 'value');
Service Providers:
$this->app->bind('tenant-repo', function () {
return new TenantRepository(Tenant::currentTenant());
});
Middleware Order:
IdentifyTenant before StartSession or Authenticate to avoid session/tenant conflicts.// app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
\Rinvex\Tenants\Http\Middleware\IdentifyTenant::class,
\Illuminate\Session\Middleware\StartSession::class,
// ...
],
];
Database Queries:
$users = User::with('tenant')->get();
class GlobalSetting extends Model
{
public function getTenantsScopes()
{
return [];
}
}
Testing:
Tenant::setCurrentTenant(null);
Tenants::withoutTenants() for cross-tenant tests:
Tenants::withoutTenants(function () {
// Test logic here
});
Performance:
domain or uuid).Tenants::withoutTenants() for bulk operations spanning tenants.Tenant Not Identified:
config/tenants.php for correct identifier.\Log::debug('Current tenant:', ['tenant' => Tenant::currentTenant()]);
Query Issues:
\DB::enableQueryLog();
User::all();
\Log::debug('Queries:', \DB::getQueryLog());
Caching Conflicts:
php artisan cache:clear
Cache::tags(['tenant:1'])->flush();
Custom Tenant Identifiers:
TenantResolver:
Tenant::resolver(function ($request) {
return Tenant::where('api_key', $request->header('X-Tenant-Key'))->first();
});
Dynamic Tenant Switching:
php artisan tenant:switch --tenant=1
Tenant-Specific Config:
$tenantConfig = config("tenants.{$currentTenant->id}");
Webhooks and Events:
Tenant::created(function ($tenant) {
\Log::info("Tenant created: {$tenant->domain}");
});
How can I help you explore Laravel packages today?