Appearance
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');
}