Skip to content

Module Manager Helpers

The Module Manager provides a set of global helper functions that simplify working with multi-tenancy, modules, configuration settings, and authorization throughout your application.

1. Multi-Tenancy Helpers

These helpers provide easy access to multi-tenancy configuration and state:

isMultiTenant(): bool

Checks if multi-tenancy is enabled in the application.

php
// Check if we need to handle tenant-specific logic
if (isMultiTenant()) {
    // Multi-tenancy is enabled, apply tenant-specific logic
}

multiDatabase(): bool

Checks if multi-database mode is enabled, which determines if each tenant has its own database.

php
if (multiDatabase()) {
    // Each tenant has its own database
}

tenantClass(): string

Gets the fully qualified class name of the tenant model configured in the application.

php
$tenantClass = tenantClass(); // e.g. 'App\Models\Company'
$tenant = new $tenantClass();

tenantIdColumn(): string

Gets the column name used for tenant IDs in the database (default is usually 'tenant_id').

php
$column = tenantIdColumn(); // e.g. 'tenant_id'
$query->where($column, $tenantId);

tenant(): ?Model

Gets the current authenticated tenant from Filament.

php
$currentTenant = tenant();
if ($currentTenant) {
    echo "Current tenant: " . $currentTenant->name;
}

tenantId(): ?int

Gets the ID of the current authenticated tenant.

php
$currentTenantId = tenantId(); // e.g. 1

tenantUserTable(): string

Gets the name of the pivot table that connects tenants and users.

php
$pivotTable = tenantUserTable(); // e.g. 'tenant_users'

tenantRelationshipName(): string

Gets the camelCase relationship name for the tenant model, derived from the class name.

php
$relationshipName = tenantRelationshipName(); // e.g. 'company'
$model->$relationshipName; // Access the tenant relationship

2. User Helpers

These helpers simplify working with users:

userClass(): string

Gets the fully qualified class name of the user model configured in the application.

php
$userClass = userClass(); // e.g. 'App\Models\User'
$user = $userClass::find(1);

user(): ?User

Gets the current authenticated user.

php
$currentUser = user();
if ($currentUser) {
    echo "Hello, " . $currentUser->name;
}

userIdColumn(): string

Gets the user ID column name used in relationship tables.

php
$column = userIdColumn(); // e.g. 'user_id'
$query->where($column, $userId);

userId(): ?int

Gets the ID of the current authenticated user.

php
$currentUserId = userId(); // e.g. 1

3. Module Utilities

These helpers assist with module identification and configuration:

getModuleNameFromClass(string|object $class): ?string

Extracts the module name from a class name or object.

php
$module = getModuleNameFromClass('Modules\Blog\Models\Post'); // Returns 'Blog'
$module = getModuleNameFromClass($postObject); // Returns 'Blog'

fromModuleManager(string $key, mixed $default): mixed

Gets module-specific configuration from the module-manager config file.

php
$blogConfig = fromModuleManager('blog.settings', ['posts_per_page' => 10]);

getModuleManagerConfig(string $key, mixed $default): mixed

Gets global module-manager configuration values.

php
$checkPermissions = getModuleManagerConfig('check_permissions', true);

4. Authorization Helpers

These helpers simplify authorization checks:

authorizeAction(string|array|AuthorizeAction $action, Model|string|null $model): bool

Authorizes an action or an array of actions for the authenticated user on a specific model.

php
// Single action check
if (authorizeAction('view', $post)) {
    // User can view the post
}

// Multiple actions with enum
if (authorizeAction([AuthorizeAction::Create, AuthorizeAction::Update], Post::class)) {
    // User can both create and update posts
}

checkPermissions(): bool

Checks if the permission verification system is enabled.

php
if (checkPermissions()) {
    // Permission checking is enabled
}

userInteractsWithModules(): string

Gets the fully qualified class name of the trait that handles user interactions with modules.

php
$traitClass = userInteractsWithModules(); // e.g. 'App\Traits\UserInteractsWithModules'
checkIfTraitIsUsed($traitClass, userClass());

tenantInteractsWithModules(): string

Gets the fully qualified class name of the trait that handles tenant interactions with modules.

php
$traitClass = tenantInteractsWithModules(); // e.g. 'App\Traits\TenantInteractsWithModules'
checkIfTraitIsUsed($traitClass, tenantClass());

5. Utility Helpers

Additional utility functions to help with common operations:

mergeTenantId(array $arrayBase, ?int $fallbackId = null): array

Automatically adds the current tenant ID to an array of attributes. Useful for creating new models.

php
$postData = [
    'title' => 'New Post',
    'content' => 'Post content'
];

// Will add tenant_id if multi-tenancy is enabled
$postData = mergeTenantId($postData, fallBackId: Company::find(1)->getKey());

Post::create($postData);

checkIfTraitIsUsed(string $trait, string $targetClass): void

Verifies if a specific trait is used in a class. Throws an exception if the trait is not used.

php
// Will throw an exception if UserInteractsWithModules trait is not used in the User class
checkIfTraitIsUsed('App\Traits\UserInteractsWithModules', 'App\Models\User');

panelColors(): array

Returns an array of available panel colors for use in UI components.

php
$colors = panelColors(); // e.g. ['primary' => [shades], 'secondary' => [shades], ...]

Usage in Multi-Tenant Applications

In a multi-tenant application, these helpers work together to provide a seamless experience:

php
// Check if multi-tenancy is enabled
if (isMultiTenant()) {
    // Get the current tenant
    $currentTenant = tenant();

    // Query only records belonging to the current tenant
    $posts = Post::query()
        ->where(tenantIdColumn(), $currentTenant->getKey())
        ->get();

    // Or simply rely on the HasTenant trait to automatically scope queries
    $posts = Post::all(); // Already scoped to current tenant if Post uses HasTenant

    // When creating records, automatically include tenant ID
    $post = Post::create(mergeTenantId([
        'title' => 'New Post',
        'content' => 'Content...'
    ]));

    // Check permissions
    if (authorizeAction('create', Post::class)) {
        // User can create posts for the current tenant
    }
}

These helpers form a cohesive system that makes multi-tenant application development more efficient and less error-prone.

Tenant Management Helpers with Central Database Support

getTenantFromSession()

Get tenant from session or URL when working with cross-database architecture.

php
function getTenantFromSession(): ?Model

Returns: ?Model - The tenant model instance or null if not found

Example:

php
$tenant = getTenantFromSession();
if ($tenant) {
    echo "Current tenant: " . $tenant->name;
}

Description: This helper attempts to retrieve the tenant from multiple sources in the following order:

  • From Filament's current tenant
  • From session storage using current_tenant_id
  • From route parameter tenant

getTenantFromCentral()

Get tenant directly from the central database by ID.

php
function getTenantFromCentral(?int $tenantId = null): ?Model

Parameters:

  • $tenantId (int|null) - The tenant ID. If null, attempts to get from session

Returns: ?Model - The tenant model instance or null if not found

Example:

php
// Get tenant with ID 5 from central database
$tenant = getTenantFromCentral(5);

// Get tenant using session ID
$tenant = getTenantFromCentral();

getTenantBySlug()

Get tenant by slug from the central database.

php
function getTenantBySlug(string $slug): ?Model

Parameters:

  • $slug (string) - The tenant's unique slug

Returns: ?Model - The tenant model instance or null if not found

Example:

php
$tenant = getTenantBySlug('acme-corporation');
if ($tenant) {
    echo "Found tenant: " . $tenant->name;
}

currentTenant()

Get current tenant handling cross-database scenarios with caching.

php
function currentTenant(): ?Model

Returns: ?Model - The current tenant model instance or null

Example:

php
$tenant = currentTenant();
if ($tenant) {
    $users = $tenant->users;
}

Description: This helper caches the tenant in the application container for performance. It checks multiple sources:

  • Application container cache
  • Filament tenant (if authenticated)
  • Session storage
  • Route parameters

setCurrentTenant()

Set the current tenant in various contexts (Filament, session, app container).

php
function setCurrentTenant(Model $tenant): void

Parameters:

  • $tenant (Model) - The tenant model to set as current

Example:

php
$tenant = Company::find(1);
setCurrentTenant($tenant);

Description: This helper sets the tenant in multiple contexts:

  • Filament (if user is authenticated)
  • Application container
  • Session storage
  • Spatie permissions team ID

getTenantUsers()

Get all users for a specific tenant from the central database.

php
function getTenantUsers(?Model $tenant = null): \Illuminate\Support\Collection

Parameters:

  • $tenant (Model|null) - The tenant model. If null, uses current tenant

Returns: Collection - Collection of user models

Example:

php
// Get users for current tenant
$users = getTenantUsers();

// Get users for specific tenant
$tenant = getTenantBySlug('acme-corporation');
$users = getTenantUsers($tenant);

foreach ($users as $user) {
    echo $user->name . PHP_EOL;
}

userBelongsToTenant()

Check if a user belongs to a specific tenant.

php
function userBelongsToTenant(?UserModel $user = null, ?Model $tenant = null): bool

Parameters:

  • $user (UserModel|null) - The user to check. If null, uses authenticated user
  • $tenant (Model|null) - The tenant to check against. If null, uses current tenant

Returns: bool - True if user belongs to tenant, false otherwise

Example:

php
// Check if current user belongs to current tenant
if (userBelongsToTenant()) {
    // User has access
}

// Check specific user and tenant
$user = User::find(1);
$tenant = Company::find(2);
if (userBelongsToTenant($user, $tenant)) {
    // User belongs to this tenant
}

switchDatabaseForTenant()

Switch to tenant's database when using multi-database architecture.

php
function switchDatabaseForTenant(?Model $tenant = null): void

Parameters:

  • $tenant (Model|null) - The tenant to switch database for. If null, uses current tenant

Example:

php
// Switch to current tenant's database
switchDatabaseForTenant();

// Switch to specific tenant's database
$tenant = getTenantBySlug('acme-corporation');
switchDatabaseForTenant($tenant);

Description: This helper only works when multiDatabase() returns true. It configures the database connection and reconnects to the tenant's database.

withCentralDatabase()

Execute a callback using the central database connection with transaction support.

php
function withCentralDatabase(callable $callback): mixed

Parameters:

  • $callback (callable) - The callback to execute within central database context

Returns: mixed - The callback's return value

Example:

php
$result = withCentralDatabase(function () {
    // All database operations here use central connection
    $tenant = Company::create([
        'name' => 'New Company',
        'slug' => 'new-company'
    ]);
    
    $tenant->users()->attach([1, 2, 3]);
    
    return $tenant;
});

withTenantDatabase()

Execute a callback using the tenant database connection with transaction support.

php
function withTenantDatabase(callable $callback, ?Model $tenant = null): mixed

Parameters:

  • $callback (callable) - The callback to execute within tenant database context
  • $tenant (Model|null) - The tenant whose database to use. If null, uses current tenant

Returns: mixed - The callback's return value

Example:

php
// Use current tenant's database
$orders = withTenantDatabase(function () {
    return Order::with('items')->get();
});

// Use specific tenant's database
$tenant = getTenantBySlug('acme-corporation');
$products = withTenantDatabase(function () {
    return Product::where('active', true)->get();
}, $tenant);

Middleware Integration

SetTenantContext Middleware

The SetTenantContext middleware automatically sets the tenant context based on route parameters.

Usage in routes:

php
Route::middleware(['set.tenant.context'])->group(function () {
    Route::get('/{tenant}/dashboard', DashboardController::class);
    Route::get('/{tenant}/kitchen', KitchenMonitor::class);
});

Middleware registration:

php
// In app/Http/Kernel.php or bootstrap/app.php
protected $middlewareAliases = [
    'set.tenant.context' => \App\Http\Middleware\SetTenantContext::class,
];

Common Usage Patterns

Pattern 1: Public Routes with Tenant Context

php
// In your Livewire component or controller
public function mount()
{
    $this->tenant = currentTenant();
    
    if (!$this->tenant) {
        abort(404, 'Tenant not found');
    }
    
    // Work with tenant data
    $this->loadTenantData();
}

Pattern 2: Cross-Database Queries

php
// Get tenant from central database
$tenant = getTenantFromCentral($tenantId);

// Get tenant's users from central database
$users = getTenantUsers($tenant);

// Execute operations in tenant's database
$orders = withTenantDatabase(function () use ($users) {
    return Order::whereIn('user_id', $users->pluck('id'))->get();
}, $tenant);

Pattern 3: Authenticated Multi-Tenant Operations

php
// Check if user has access to tenant
if (!userBelongsToTenant()) {
    abort(403, 'Unauthorized access to this tenant');
}

// Set tenant context
setCurrentTenant($tenant);

// Now all operations use this tenant context
$data = SomeModel::all(); // Automatically scoped to tenant

Configuration Requirements

These helpers require the following configuration in config/module-manager.php:

php
return [
    'multi_tenancy' => true,
    'multi_database' => true, // Set to true for multi-database setup
    'tenant_class' => \App\Models\Company::class,
    'user_class' => \App\Models\User::class,
    'tenant_id_column' => 'company_id',
    'user_id_column' => 'user_id',
    'tenant_user_table' => 'company_user',
];

Database Connections

For multi-database support, configure your config/database.php:

php
'connections' => [
    'central' => [
        'driver' => 'mysql',
        'database' => env('DB_CENTRAL_DATABASE', 'central'),
        // ... other settings
    ],
    
    'tenant' => [
        'driver' => 'mysql',
        'database' => null, // Dynamically set
        // ... other settings
    ],
],

Error Handling

All helpers are designed to fail gracefully:

php
// Safe to use - returns null if tenant not found
$tenant = currentTenant();

// Check before using
if ($tenant) {
    // Proceed with tenant operations
} else {
    // Handle missing tenant case
    abort(404, 'Tenant not found');
}