### Configure Database per Tenant Setup in Laravel Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt This snippet shows how to configure the `config/tenancy.php` file for database separation. It defines central and tenant database connections, connection prefixes, and migration parameters. It also includes an example of creating tenant-specific user tables and how to run migrations for all tenants using Artisan. ```php // config/tenancy.php return [ 'database' => [ 'central_connection' => 'central', 'template_tenant_connection' => 'tenant', 'prefix' => 'tenant_', 'suffix' => '', ], 'migration_parameters' => [ '--force' => true, '--path' => ['database/migrations/tenant'], ], ]; // database/migrations/tenant/2024_01_01_000001_create_tenant_users_table.php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up() { Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->string('password'); $table->string('role')->default('user'); $table->timestamps(); }); } }; // Run migrations for all tenants use Stancl\Tenancy\Database\Models\Tenant; Tenant::all()->each(function (Tenant $tenant) { $tenant->run(function () { Artisan::call('migrate', [ '--path' => 'database/migrations/tenant', '--force' => true, ]); }); }); // Or use the built-in command // php artisan tenants:migrate ``` -------------------------------- ### Define Universal and Tenant-Specific Routes in Laravel Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt This snippet demonstrates how to define routes for both the central application and tenant-specific applications within a Laravel project. It includes examples of registering new tenants and accessing tenant-specific routes using middleware. Dependencies include Laravel's routing system and the Stancl/Tenancy package. ```php // routes/web.php - Central routes (all tenants) Route::get('/', function () { return view('landing'); }); Route::post('/register-tenant', function (Request $request) { $tenant = Tenant::create([ 'id' => $request->subdomain, 'name' => $request->company_name, 'email' => $request->email, ]); $tenant->domains()->create([ 'domain' => "{$request->subdomain}.myapp.com" ]); return redirect("https://{$request->subdomain}.myapp.com/setup"); }); // routes/tenant.php - Tenant-specific routes Route::middleware(['web', 'tenancy'])->group(function () { Route::get('/setup', function () { // Only accessible from tenant domains return view('tenant.setup', ['tenant' => tenant()]); }); Route::get('/api/data', function () { return User::with('projects')->paginate(20); }); }); ``` -------------------------------- ### Configure Laravel Tenancy Middleware for Domain, Path, and Request Identification Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt This code illustrates how to configure middleware groups and aliases in Laravel's `app/Http/Kernel.php` for tenant identification. It demonstrates setting up different middleware ('tenancy', 'tenancy.path', 'tenancy.request') to handle tenant resolution based on domain, URL path, or request headers/parameters, respectively, and shows example route definitions for each strategy. ```php // app/Http/Kernel.php protected $middlewareGroups = [ 'web' => [ // ... standard middleware ], 'tenant' => [ 'web', \Stancl\Tenancy\Middleware\InitializeTenancyByDomain::class, \Stancl\Tenancy\Middleware\PreventAccessFromCentralDomains::class, ], ]; protected $middlewareAliases = [ 'tenancy' => \Stancl\Tenancy\Middleware\InitializeTenancyByDomain::class, 'tenancy.path' => \Stancl\Tenancy\Middleware\InitializeTenancyByPath::class, 'tenancy.request' => \Stancl\Tenancy\Middleware\InitializeTenancyByRequestData::class, ]; // routes/tenant.php - Multiple identification strategies Route::middleware(['web', 'tenancy'])->group(function () { // Identified by domain (acme.myapp.com) Route::get('/dashboard', [DashboardController::class, 'index']); }); Route::middleware(['web', 'tenancy.path'])->group(function () { // Identified by path (/acme-corp/api/users) Route::prefix('{tenant}')->group(function () { Route::apiResource('users', UserController::class); }); }); Route::middleware(['web', 'tenancy.request'])->group(function () { // Identified by request header or parameter // X-Tenant-ID: acme-corp Route::post('/webhook', [WebhookController::class, 'handle']); }); ``` -------------------------------- ### Customize Laravel Tenant Model with Custom Attributes and Seeding Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt This example shows how to extend the base Tenant model in Laravel to include custom attributes like 'plan', 'trial_ends_at', and 'settings'. It also includes custom methods for checking trial status and plan type, and a seedDatabase method for initializing tenant-specific data upon creation. Configuration updates are required in `config/tenancy.php`. ```php // app/Models/Tenant.php namespace App\Models; use Stancl\Tenancy\Database\Models\Tenant as BaseTenant; use Stancl\Tenancy\Database\Concerns\HasDatabase; use Stancl\Tenancy\Database\Concerns\HasDomains; class Tenant extends BaseTenant { use HasDatabase, HasDomains; // Add custom attributes protected $fillable = [ 'id', 'name', 'email', 'plan', 'trial_ends_at', 'subscription_id', 'settings', ]; protected $casts = [ 'trial_ends_at' => 'datetime', 'settings' => 'array', ]; // Custom methods public function isOnTrial(): bool { return $this->trial_ends_at && $this->trial_ends_at->isFuture(); } public function isPremium(): bool { return in_array($this->plan, ['premium', 'enterprise']); } public function users() { return $this->hasMany(User::class)->using(TenantPivot::class); } // Seed initial data when tenant is created public function seedDatabase() { $this->run(function () { // Create default roles $roles = ['admin', 'manager', 'user']; foreach ($roles as $role) { Role::create(['name' => $role]); } // Create default settings Setting::create([ 'theme' => 'light', 'timezone' => 'UTC', 'language' => 'en', ]); }); } } // Update config to use custom model // config/tenancy.php return [ 'tenant_model' => \App\Models\Tenant::class, ]; ``` -------------------------------- ### Isolate Cache and Storage in Laravel Tenancy Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt This configuration snippet from `config/tenancy.php` enables filesystem suffixing and cache tagging for tenant isolation. It demonstrates how to upload and retrieve files within a tenant's specific storage directory and how cache is automatically scoped per tenant, preventing data leakage between them. The example routes show practical implementation for file uploads and cache-driven data retrieval. ```php // config/tenancy.php return [ 'filesystem' => [ 'suffix_base' => 'tenant', 'disks' => ['local', 'public', 's3'], ], 'cache' => [ 'tag_base' => 'tenant', ], ]; // Tenant-specific file storage Route::middleware(['tenancy'])->group(function () { Route::post('/upload', function (Request $request) { // Tenant context is automatically applied $path = $request->file('document')->store('documents', 'public'); // Stored in: storage/app/public/tenant{id}/documents/ // Retrieve from tenant storage $url = Storage::disk('public')->url($path); return ['url' => $url, 'path' => $path]; }); Route::get('/documents/{filename}', function ($filename) { // Automatically reads from current tenant's storage return Storage::disk('public')->download("documents/{$filename}"); }); }); // Tenant-specific caching Route::get('/dashboard', function () { // Cache is automatically scoped to current tenant $stats = Cache::remember('dashboard.stats', 3600, function () { return [ 'users' => User::count(), 'revenue' => Order::sum('total'), 'projects' => Project::count(), ]; }); return view('dashboard', $stats); }); // Each tenant has isolated cache: // Tenant acme-corp: cache key -> tenant:acme-corp:dashboard.stats // Tenant techstart-inc: cache key -> tenant:techstart-inc:dashboard.stats ``` -------------------------------- ### Dispatch Queue Jobs with Tenant Context in Laravel Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt This PHP code demonstrates how to create a tenant-aware queue job in Laravel using the `TenantAware` trait. The `GenerateReport` job automatically executes within the correct tenant's context. The example shows dispatching this job from a route, ensuring that any database operations or notifications within the job are scoped to the tenant that initiated the request. ```php // app/Jobs/GenerateReport.php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Stancl\Tenancy\Contracts\Tenant; use Stancl\Tenancy\Jobs\TenantAware; class GenerateReport implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, TenantAware; public function __construct( public string $reportType, public array $filters, ) {} public function handle() { // Job automatically runs in tenant context $data = match($this->reportType) { 'sales' => Order::whereBetween('created_at', [ $this->filters['start_date'], $this->filters['end_date'] ])->get(), 'users' => User::where('active', true)->get(), default => throw new \Exception('Invalid report type'), }; $report = Report::create([ 'type' => $this->reportType, 'data' => $data->toArray(), 'generated_at' => now(), ]); // Notify tenant users User::where('role', 'admin')->each(function ($user) use ($report) { $user->notify(new ReportGenerated($report)); }); } } // Dispatch from tenant context Route::post('/reports/generate', function (Request $request) { // Current tenant context is preserved in the job GenerateReport::dispatch( $request->input('type'), $request->input('filters') ); return ['message' => 'Report generation started']; }); ``` -------------------------------- ### Multi-Database Tenancy in PHP Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt Demonstrates how to create, initialize, and switch between tenants when using a multi-database tenancy approach. It shows how Eloquent queries are automatically scoped to the current tenant's database after initialization. Dependencies include the StanclTenancy package. ```php use Stancl\Tenancy\Database\Models\Tenant; use Stancl\Tenancy\Database\TenantCollection; // Create a new tenant with dedicated database $tenant = Tenant::create([ 'id' => 'acme-corp', 'plan' => 'premium' ]); // The tenant's database is automatically created // All subsequent operations for this tenant use their database tenancy()->initialize($tenant); // Now all Eloquent queries use the tenant's database $users = User::all(); // Users from acme-corp's database only $orders = Order::where('status', 'pending')->get(); // Switch to another tenant $anotherTenant = Tenant::find('techstart-inc'); tenancy()->initialize($anotherTenant); // Now queries use techstart-inc's database $users = User::all(); // Different set of users ``` -------------------------------- ### Creating and Managing Tenants in Laravel Tenancy Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt Programmatically create, manage, and delete tenants within the Tenancy for Laravel framework. This includes adding custom data, associating domains, updating tenant information, and running tenant-specific operations. ```php use Stancl\Tenancy\Database\Models\Tenant; use Stancl\Tenancy\Database\Models\Domain; // Create tenant with custom data $tenant = Tenant::create([ 'id' => 'acme-corp', 'name' => 'Acme Corporation', 'email' => 'admin@acme.com', 'plan' => 'enterprise', 'trial_ends_at' => now()->addDays(14), ]); // Add multiple domains to a tenant $tenant->domains()->createMany([ ['domain' => 'acme.myapp.com'], ['domain' => 'acme-corp.com'], ['domain' => 'www.acme-corp.com'], ]); // Access tenant data $planName = $tenant->plan; // 'enterprise' $allDomains = $tenant->domains; // Collection of Domain models // Update tenant $tenant->update(['plan' => 'premium']); // Run tenant-specific operations $tenant->run(function () { // This closure executes in the tenant's context User::create([ 'name' => 'John Admin', 'email' => 'john@acme.com', 'role' => 'admin', ]); // Seed initial data for new tenant DB::table('settings')->insert([ 'key' => 'theme', 'value' => 'dark', ]); }); // Delete tenant and all their data $tenant->delete(); // Drops database and removes all records ``` -------------------------------- ### Tenant Identification by Domain Configuration in PHP Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt Shows how to enable and configure domain-based tenant identification within the Tenancy for Laravel package. It includes configuration settings and seeder code to associate domains with tenants, enabling automatic tenant context switching based on the accessed domain. Requires the StanclTenancy package. ```php // config/tenancy.php return [ 'identification' => [ 'domain' => [ 'enabled' => true, ], ], ]; // database/seeders/TenantSeeder.php use Stancl\Tenancy\Database\Models\Domain; use Stancl\Tenancy\Database\Models\Tenant; $acme = Tenant::create(['id' => 'acme-corp']); $acme->domains()->create(['domain' => 'acme.myapp.com']); $techstart = Tenant::create(['id' => 'techstart-inc']); $techstart->domains()->create(['domain' => 'techstart.myapp.com']); // routes/web.php - These routes are tenant-aware Route::middleware(['web', 'tenancy'])->group(function () { Route::get('/dashboard', function () { // When accessed via acme.myapp.com // Current tenant is automatically 'acme-corp' $tenant = tenant(); // Returns acme-corp tenant $users = User::all(); // Acme's users only return view('dashboard', [ 'tenant' => $tenant, 'users' => $users ]); }); Route::get('/settings', [SettingsController::class, 'show']); }); // Accessing https://acme.myapp.com/dashboard automatically identifies // and initializes the 'acme-corp' tenant context ``` -------------------------------- ### Single-Database Tenancy with Model Traits in PHP Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt Illustrates how to implement single-database tenancy by scoping models using the `BelongsToTenant` trait. It shows automatic scoping for Eloquent create and query operations based on the currently initialized tenant. Requires the StanclTenancy package. ```php use Stancl\Tenancy\Database\Concerns\BelongsToTenant; use Illuminate\Database\Eloquent\Model; // Define a tenant-scoped model class Task extends Model { use BelongsToTenant; protected $fillable = ['title', 'description', 'status']; } // Set current tenant context tenancy()->initialize(Tenant::find('acme-corp')); // Create task - automatically scoped to current tenant $task = Task::create([ 'title' => 'Deploy new feature', 'description' => 'Deploy the analytics dashboard', 'status' => 'pending' ]); // SQL: INSERT INTO tasks (title, description, status, tenant_id) // VALUES ('Deploy...', '...', 'pending', 'acme-corp') // Query tasks - automatically filtered to current tenant $pendingTasks = Task::where('status', 'pending')->get(); // SQL: SELECT * FROM tasks WHERE status = 'pending' AND tenant_id = 'acme-corp' // Switch tenant tenancy()->initialize(Tenant::find('techstart-inc')); $techstartTasks = Task::all(); // Only techstart-inc's tasks ``` -------------------------------- ### Tenant Lifecycle Event System in Laravel Tenancy Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt Listen to and handle tenant lifecycle events (creation, initialization, deletion) in Laravel Tenancy to implement custom business logic. This involves registering event listeners within a Service Provider. ```php // app/Providers/TenancyServiceProvider.php namespace App\Providers; use Stancl\Tenancy\Events\TenantCreated; use Stancl\Tenancy\Events\TenantDeleted; use Stancl\Tenancy\Events\TenancyInitialized; use Stancl\Tenancy\Events\TenancyEnded; use Illuminate\Support\Facades\Event; use Illuminate\Support\ServiceProvider; class TenancyServiceProvider extends ServiceProvider { public function boot() { // Triggered when a new tenant is created Event::listen(TenantCreated::class, function (TenantCreated $event) { $tenant = $event->tenant; // Send welcome email Mail::to($tenant->email)->send(new WelcomeEmail($tenant)); // Create default admin user $tenant->run(function () use ($tenant) { User::create([ 'name' => 'Admin', 'email' => $tenant->email, 'password' => bcrypt(Str::random(16)), 'role' => 'admin', ]); }); // Log tenant creation Log::info("Tenant created: {$tenant->id}"); }); // Triggered when tenant context is initialized Event::listen(TenancyInitialized::class, function (TenancyInitialized $event) { $tenant = $event->tenancy->tenant; // Set tenant-specific configuration config(['app.name' => $tenant->name]); config(['mail.from.name' => $tenant->name]); // Track tenant activity Redis::zincrby('tenant:activity', 1, $tenant->id); }); // Triggered when tenant is deleted Event::listen(TenantDeleted::class, function (TenantDeleted $event) { $tenant = $event->tenant; // Cleanup tenant files Storage::disk('s3')->deleteDirectory("tenants/{$tenant->id}"); // Cancel subscriptions Stripe::subscription($tenant->subscription_id)->cancel(); Log::info("Tenant deleted: {$tenant->id}"); }); } } ``` -------------------------------- ### Tenant Identification by Path in Laravel Source: https://context7.com/context7/tenancyforlaravel_com-docs-v3-introduction/llms.txt Configure Laravel Tenancy to identify tenants based on URL path segments. This is useful for multi-tenant applications that do not use custom domains. It requires modifying the tenancy configuration file and route definitions. ```php // config/tenancy.php return [ 'identification' => [ 'path' => [ 'enabled' => true, 'position' => 0, // Tenant ID is first path segment ], ], ]; // routes/tenant.php Route::middleware(['web', 'tenancy'])->group(function () { Route::prefix('{tenant}')->group(function () { Route::get('/dashboard', function () { // URL: /acme-corp/dashboard // Tenant 'acme-corp' is automatically identified $currentTenant = tenant('id'); // 'acme-corp' $stats = [ 'users' => User::count(), 'active_projects' => Project::where('status', 'active')->count(), 'tenant_name' => tenant('name'), ]; return view('dashboard', $stats); }); // URL: /techstart-inc/projects Route::get('/projects', [ProjectController::class, 'index']); }); }); // Each URL automatically identifies the tenant: // /acme-corp/dashboard -> tenant: acme-corp // /techstart-inc/dashboard -> tenant: techstart-inc ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.