Selective Multi-tenancy

Hello!. Filament v3 Multi-tenancy is dope. but it assumes all Models are multi-tenant. Is it possible to exclude some Models and their Filament Resources from Multi-tenancy? My current solution is to have multiple panels configured for multi-tenancy except one (AdminPanelServiceProvider ). All non multi-tenant Models and Resources are excluded from the multi-tenant panels.
14 Replies
Patrick Boivin
Patrick Boivin16mo ago
I think the multiple panel approach is the most common so far. There are older threads here documenting some experiments to modify the resource queries to remove tenancy and things like that, all in one panel. But I'm not sure if there is a clear alternative.
davidl
davidl16mo ago
What about using Nova for the admin stuff?
Patrick Boivin
Patrick Boivin16mo ago
Can you expand on this a bit? How does it solve the issue?
vbezruchkin
vbezruchkin16mo ago
Hi, I have precisely the same question. I do have some Models, that are global and some Models that are only applicable to a tenant company. We actively use Nova in other projects, but having two separate areas would be a real overhead. I wonder if there is any plan to improve this and allow an easier way to specify Global vs Tenant Models. Here is an example: It would be nice to have some great plugins like Audit log, Auth log, etc. They should be global for admin panel, but now it only allows them as part of multi-tenant system 😦 We had to re-invent some hacks to make them work. Thanks! I guess the advice is to use a separate area where you control non-tenant models. so it's like admin only stuff, where super admins can login and configure those models.
Patrick Boivin
Patrick Boivin16mo ago
It makes sense. As discussed here, you can use multiple panels within a single Filament app to achieve this. Another option is to implement a different solution for tenancy instead of the built-in (using a Laravel package, for example). I can't speak for the core team but if I had to guess, I'd say that it's very likely to improve in the future, regarding Global vs Tenant Models.
vbezruchkin
vbezruchkin16mo ago
Thanks for the reply. Yes, for me it also sounds like a nice plan for the plugin future 🙂 Let's hope we have some solidarity with the plugin development team.
@uwascan
@uwascanOP16mo ago
Thank you for your responses. I actually found a nice way to solve the problem and I provided an answer to another related question. I will provide an update soon. Never be afraid to look under the hood!!!
Crylar
Crylar16mo ago
Any update on the topic? 🙂
sweetplum
sweetplum16mo ago
yeah, would like to know how you did it too
@uwascan
@uwascanOP15mo ago
Here is what I did. Create a marker interface to Identify Models that are multitenant.
interface IMultiTenantModel
{

}
interface IMultiTenantModel
{

}
Create a new Base Class for your resources
abstract class AppBaseResource extends Resource
{
public static function getEloquentQuery(): Builder
{
$query = static::getModel()::query();

if ($tenant = Filament::getTenant()) {
if (app(static::getModel()) instanceof IMultiTenantModel) {
static::scopeEloquentQueryToTenant($query, $tenant);
}
}

return $query;
}
}
abstract class AppBaseResource extends Resource
{
public static function getEloquentQuery(): Builder
{
$query = static::getModel()::query();

if ($tenant = Filament::getTenant()) {
if (app(static::getModel()) instanceof IMultiTenantModel) {
static::scopeEloquentQueryToTenant($query, $tenant);
}
}

return $query;
}
}
You may create a base class for your Create Pages as shown below:
class AppCreateRecord extends Page
{
/**
* @param array<string, mixed> $data
*/
protected function handleRecordCreation(array $data): Model
{
$record = new ($this->getModel())($data);

if ($tenant = Filament::getTenant()) {
if (app(static::getModel()) instanceof IMultiTenantModel) {
return $this->associateRecordWithTenant($record, $tenant);
}
}

$record->save();

return $record;
}
}
class AppCreateRecord extends Page
{
/**
* @param array<string, mixed> $data
*/
protected function handleRecordCreation(array $data): Model
{
$record = new ($this->getModel())($data);

if ($tenant = Filament::getTenant()) {
if (app(static::getModel()) instanceof IMultiTenantModel) {
return $this->associateRecordWithTenant($record, $tenant);
}
}

$record->save();

return $record;
}
}
Make sure to extend the base classes above for any Resource that you add to a multitenant Panel. This will allow but multitenant Models and other models that are not multitenant to be used in all panels
SirFat
SirFat15mo ago
That's pretty clever.
Crylar
Crylar15mo ago
Unfortunately, you still can't mix shared with tenant related resources because of the url. I wish we could have shared stuff above the dropdown with global urls :/
SirFat
SirFat15mo ago
I thought there was a way to selectively customise the URL
Timster8989
Timster898915mo ago
I have all my models extend one base model which defines QueryLimiter. Inside this I define limits for each table that requires multi tenancy. This helps to keep limit logic in one place and keeps the code very compact. Beauty of Eloquent.

Did you find this page helpful?