PHP Laravel

Fixing Tenant Scoping with TenantAwareBuilder in Laravel

The Problem

In multi-tenant Laravel applications built with Filament, scoping data to the current tenant is crucial. We encountered an issue where Filament's multi-tenancy implementation, using whereIn() for tenant scoping, failed when applied to tenant schema tables lacking a company_id column. This resulted in "column 'company_id' does not exist" errors across Filament resources.

The Solution

The existing where() override was insufficient to handle the whereIn() calls used by Filament. To address this, we overrode the whereIn method within the TenantAwareBuilder class. This ensures that when tenant scoping is applied to tables without a company_id column, the scoping is gracefully skipped, preventing the errors.

Consider a scenario where you have a products table that is tenant-specific but doesn't contain a company_id column. Filament's attempt to scope queries using whereIn('company_id', [...]) would fail. The fix involves intercepting this call and conditionally omitting the whereIn clause based on the table's structure.

Here's an illustrative example of how the whereIn override might look (note: this is conceptual, as actual code was not provided in the context):

namespace App\Builders;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Schema;

class TenantAwareBuilder extends Builder
{
    public function whereIn($column, $values, $boolean = 'and', $not = false)
    {
        if ($column === 'company_id' && ! Schema::hasColumn($this->getModel()->getTable(), 'company_id')) {
            return $this; // Skip the whereIn clause
        }

        return parent::whereIn($column, $values, $boolean, $not);
    }
}

In this example, we check if the column being queried is company_id and if the table associated with the model has that column. If the column doesn't exist, we simply return the builder instance without adding the whereIn clause, effectively skipping the tenant scoping for that particular table.

Key Insight

Overriding framework methods requires careful consideration of side effects. In this case, ensuring that tenant scoping doesn't break queries on tenant-specific tables without a company_id column was crucial for maintaining the functionality of Filament resources.

Actionable Takeaway: When working with multi-tenant applications and shared schemas, always validate the existence of tenant identifier columns before applying scoping logic. This prevents unexpected errors and ensures a smooth user experience.

Fixing Tenant Scoping with TenantAwareBuilder in Laravel
GERARDO RUIZ

GERARDO RUIZ

Author

Share: