Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Tenants Laravel Package

rinvex/laravel-tenants

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require rinvex/laravel-tenants
    php artisan rinvex:publish:tenants
    php artisan rinvex:migrate:tenants
    
    • Focus on config/tenants.php to define your tenant model (default: Rinvex\Tenants\Models\Tenant) and tenant identifier (e.g., domain or uuid).
  2. First Use Case: Tenant Identification

    • Use middleware to identify tenants via domain or subdomain:
      // app/Http/Kernel.php
      'identify-tenant' => \Rinvex\Tenants\Http\Middleware\IdentifyTenant::class,
      
    • Add to $middlewareGroups['web'] or create a custom group.
  3. Quick Test:

    • Create a tenant record manually (e.g., via Tinker):
      $tenant = \App\Models\Tenant::create(['domain' => 'tenant1.example.com']);
      
    • Visit tenant1.example.com in your browser to verify tenant isolation.

Implementation Patterns

Core Workflows

  1. Tenant Isolation:

    • Global Scopes: Automatically apply tenant-specific scopes to models:
      use Rinvex\Tenants\Traits\HasTenants;
      
      class User extends Model
      {
          use HasTenants;
      }
      
    • Shared vs. Isolated Data:
      • Mark models for isolation via HasTenants trait or tenant() method:
        class Project extends Model
        {
            public function tenant()
            {
                return $this->belongsTo(Tenant::class);
            }
        }
        
  2. Middleware Integration:

    • Dynamic Tenant Switching:
      // 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);
      }
      
  3. APIs and Tenant Context:

    • Access current tenant in controllers:
      $currentTenant = Tenant::currentTenant();
      
    • Pass tenant context to API responses:
      return response()->json(['tenant_id' => $currentTenant->id]);
      
  4. Seeding and Testing:

    • Use Tenant::setCurrentTenant() in tests or seeders:
      Tenant::setCurrentTenant($tenant);
      User::factory()->create();
      

Integration Tips

  1. Laravel Scout:

    • Extend HasTenants for search isolation:
      use Rinvex\Tenants\Traits\HasTenants;
      use Laravel\Scout\Searchable;
      
      class Product extends Model
      {
          use HasTenants, Searchable;
      }
      
  2. Queues and Jobs:

    • Resolve tenant context in jobs:
      public function handle()
      {
          $tenant = Tenant::currentTenant();
          // Job logic...
      }
      
  3. Caching:

    • Cache tenant-specific data with tags:
      Cache::tags(['tenant:' . $tenant->id])->put('key', 'value');
      
  4. Service Providers:

    • Bind tenant-aware repositories:
      $this->app->bind('tenant-repo', function () {
          return new TenantRepository(Tenant::currentTenant());
      });
      

Gotchas and Tips

Pitfalls

  1. Middleware Order:

    • Place IdentifyTenant before StartSession or Authenticate to avoid session/tenant conflicts.
    • Example:
      // app/Http/Kernel.php
      protected $middlewareGroups = [
          'web' => [
              \Rinvex\Tenants\Http\Middleware\IdentifyTenant::class,
              \Illuminate\Session\Middleware\StartSession::class,
              // ...
          ],
      ];
      
  2. Database Queries:

    • N+1 Queries: Eager-load tenant relationships:
      $users = User::with('tenant')->get();
      
    • Global Scopes: Disable for non-tenant models:
      class GlobalSetting extends Model
      {
          public function getTenantsScopes()
          {
              return [];
          }
      }
      
  3. Testing:

    • Tenant Context Leaks: Reset tenant after tests:
      Tenant::setCurrentTenant(null);
      
    • Database Transactions: Use Tenants::withoutTenants() for cross-tenant tests:
      Tenants::withoutTenants(function () {
          // Test logic here
      });
      
  4. Performance:

    • Indexing: Add indexes to tenant identifier columns (e.g., domain or uuid).
    • Batch Operations: Use Tenants::withoutTenants() for bulk operations spanning tenants.

Debugging

  1. Tenant Not Identified:

    • Check middleware order and config/tenants.php for correct identifier.
    • Log tenant resolution:
      \Log::debug('Current tenant:', ['tenant' => Tenant::currentTenant()]);
      
  2. Query Issues:

    • Verify global scopes are applied:
      \DB::enableQueryLog();
      User::all();
      \Log::debug('Queries:', \DB::getQueryLog());
      
  3. Caching Conflicts:

    • Clear tenant-specific cache tags:
      php artisan cache:clear
      
    • Or manually:
      Cache::tags(['tenant:1'])->flush();
      

Extension Points

  1. Custom Tenant Identifiers:

    • Override TenantResolver:
      Tenant::resolver(function ($request) {
          return Tenant::where('api_key', $request->header('X-Tenant-Key'))->first();
      });
      
  2. Dynamic Tenant Switching:

    • Create a command to switch tenants:
      php artisan tenant:switch --tenant=1
      
    • Implement via artisan command or middleware.
  3. Tenant-Specific Config:

    • Load tenant-specific config:
      $tenantConfig = config("tenants.{$currentTenant->id}");
      
  4. Webhooks and Events:

    • Listen for tenant events:
      Tenant::created(function ($tenant) {
          \Log::info("Tenant created: {$tenant->domain}");
      });
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle