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

Multi Tenant Laravel Package

hyn/multi-tenant

View on GitHub
Deep Wiki
Context7

Getting Started

First Steps

  1. Installation

    composer require hyn/multi-tenant
    

    Publish the package config and migrations:

    php artisan vendor:publish --provider="Hyn\MultiTenant\MultiTenantServiceProvider"
    php artisan migrate
    
  2. Basic Tenant Setup

    • Define a tenant() middleware in app/Http/Kernel.php:
      protected $middlewareGroups = [
          'web' => [
              // ...
              \Hyn\MultiTenant\Middleware\InitializeTenancyByDomain::class,
          ],
      ];
      
    • Configure domains in .env:
      TENANCY_DOMAINS=tenant1.example.com,tenant2.example.com
      
  3. First Use Case: Isolating Tenant Data

    • Use tenant() helper to switch contexts:
      $tenant = tenant('tenant1');
      $tenant->activate(); // Automatically scoped queries to tenant1's database
      
    • Test with a custom domain (e.g., tenant1.example.com) and verify data isolation.

Implementation Patterns

Core Workflows

  1. Tenant Activation

    • Domain-Based Routing: Leverage InitializeTenancyByDomain to auto-activate tenants via subdomains.
    • Manual Activation: Use tenant()->activate() in API routes or CLI scripts:
      $tenant = tenant()->findOrFail($request->tenant_id);
      $tenant->activate();
      
  2. Database Scoping

    • Query Scoping: All Eloquent queries auto-scope to the active tenant’s database:
      $users = User::all(); // Only returns users for the active tenant
      
    • Global Scoping: Disable for cross-tenant queries:
      User::withoutGlobalScopes()->get(); // Unscoped query
      
  3. Middleware Integration

    • Custom Tenant Resolution: Extend InitializeTenancyByDomain for non-domain logic (e.g., API keys):
      public function resolve()
      {
          $tenant = Tenant::where('api_key', $request->header('X-Tenant-Key'))->first();
          return $tenant ?: null;
      }
      
  4. CLI & Testing

    • Tenant Switching in Tinker:
      php artisan tinker
      >>> tenant('tenant1')->activate();
      
    • Testing: Use Tenancy::actingAs() to simulate tenants:
      Tenancy::actingAs(Tenant::find(1), function () {
          // Test as tenant1
      });
      

Gotchas and Tips

Common Pitfalls

  1. Database Connection Confusion

    • Issue: Forgetting to call activate() before queries.
    • Fix: Use tenant()->activate() in middleware or services.
    • Debug: Check DB::connection()->getDatabaseName() to verify the active tenant’s DB.
  2. Migration Pitfalls

    • Issue: Tenant-specific migrations may fail if run without context.
    • Fix: Use php artisan tenant:migrate tenant1 or wrap in Tenancy::actingAs().
  3. Caching Quirks

    • Issue: Cached routes/config may persist across tenants.
    • Fix: Clear cache per tenant or use Tenancy::actingAs() in cached views.
  4. Queue Jobs

    • Issue: Queued jobs may run in the wrong tenant context.
    • Fix: Dispatch jobs with the tenant ID:
      Tenancy::actingAs($tenant, function () {
          YourJob::dispatch();
      });
      

Pro Tips

  1. Dynamic Tenant Creation

    • Use Tenant::create() with a database name (e.g., tenant_db_1):
      $tenant = Tenant::create([
          'identifier' => 'tenant1',
          'database' => 'tenant_db_1',
      ]);
      
  2. Shared vs. Isolated Data

    • Shared Tables: Use shared() to mark models for cross-tenant access:
      class Setting extends Model
      {
          use \Hyn\MultiTenant\Traits\UsesTenancy;
          protected $shared = true;
      }
      
  3. Performance

    • Index Tenant ID: Add tenant_id to frequently queried tables for faster joins.
    • Connection Pooling: Use pgsql or mysql with connection pooling to avoid overhead.
  4. Debugging

    • Log Tenant Context: Add a middleware to log the active tenant:
      public function handle($request, Closure $next)
      {
          \Log::info('Active Tenant:', ['tenant' => tenant()]);
          return $next($request);
      }
      
    • Tenancy Events: Listen for tenancy.activated/tenancy.deactivated:
      event(new TenancyActivated($tenant));
      
  5. Extending Tenancy

    • Custom Tenant Models: Extend Hyn\MultiTenant\Models\Tenant for custom fields.
    • Hooks: Override resolve() in middleware for custom resolution logic.
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.
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
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope