Skip to content

Tenancy ​

The library can keep every tenant's files apart. Folders, files and tags carry a tenant, uploads are stamped with it, and every query is filtered by it. Tenancy is off until a panel with tenancy, or your config, turns it on.

Filament panel tenancy ​

Nothing to configure. When the panel uses ->tenant(Team::class), the plugin turns tenancy on and resolves the tenant with Filament::getTenant().

php
use Hoceineel\FilamentMediaLibrary\FilamentMediaLibraryPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->tenant(Team::class)
        ->plugin(FilamentMediaLibraryPlugin::make());
}

Everything is scoped to the current tenant:

WhatHow it is scoped
Files, folders and tagsA tenant_type and tenant_id column on each table, filtered by a global scope.
New recordsStamped with the current tenant when they are created.
Upload and download routesRegistered as tenant routes, so the tenant is in the URL, for example /studio/media-library/upload.
Picker validationThe picker field rejects ids that belong to another tenant.
AttachmentssyncMediaLibraryItems() drops ids from another tenant.
Rich editorThe rich editor plugin never inserts another tenant's files.
QuotaCounted per tenant. See below.

In strict mode, which is on for Filament tenancy, a request with no resolved tenant sees nothing at all.

stancl/tenancy, single database ​

Store every tenant in one database with a tenant_id column, and resolve the tenant from stancl:

php
use Hoceineel\FilamentMediaLibrary\Tenancy\StanclTenantResolver;

FilamentMediaLibraryPlugin::make()
    ->tenancy()
    ->resolveTenantUsing(StanclTenantResolver::class);

StanclTenantResolver calls stancl's tenant() helper. It returns the tenant model, or null when stancl has not been initialised for the request.

WARNING

On a panel without Filament tenancy, the plugin's strict argument has no effect: the library does not hide files when no tenant resolves. Make sure stancl's tenancy middleware runs on the panel's routes. For pages outside panels, use the tenancy.strict config key instead.

stancl/tenancy, database per tenant ​

The library tables live in each tenant's database, so the database already isolates tenants.

  1. Add the package migration to your tenant migrations.
  2. Keep tenancy.enabled set to false.
  3. Enable stancl's FilesystemTenancyBootstrapper, so each tenant writes to its own disk path.

Custom resolver ​

Pass a closure, a class name or a TenantResolver instance to resolveTenantUsing():

php
FilamentMediaLibraryPlugin::make()
    ->tenancy()
    ->resolveTenantUsing(fn () => auth()->user()?->organization);

A resolver class implements one method and returns an Eloquent model, or null:

php
use Hoceineel\FilamentMediaLibrary\Tenancy\TenantResolver;
use Illuminate\Database\Eloquent\Model;

class OrganizationResolver implements TenantResolver
{
    public function resolve(): ?Model
    {
        return auth()->user()?->organization;
    }
}

The tenant is stored as a morph (tenant_type and tenant_id), so it can be any model. The tenant_id column type follows key_types.tenant in the config. Set it to uuid, ulid or string before you run the migration if your tenants do not use integer keys.

Strict mode ​

StrictWhen no tenant resolves
onEvery query returns nothing. Safe by default.
offThe tenant filter is skipped, so the library shows every record.

Leave strict mode on unless you know why you need otherwise. A missing tenant then shows an empty library, not another tenant's files.

Standalone pages ​

Pages outside panels have no panel tenant. Turn tenancy on in config/filament-media-library.php and give it a resolver:

php
'tenancy' => [
    'enabled' => true,
    'resolver' => App\Support\CurrentTeamResolver::class,
    'strict' => true,
],
KeyDefaultMeaning
enabledfalseScope the library to a tenant outside panels.
resolverFilamentTenantResolverA class implementing TenantResolver.
stricttrueHide everything when no tenant resolves.

The default resolver reads the Filament panel tenant, which does not exist outside a panel, so always set your own. Panels with tenancy keep using their own tenant, whatever this config says. See Outside Panels.

Quotas ​

Limit storage per tenant, or for the whole app when tenancy is off:

php
'quota' => 5 * 1024 ** 3,
'quota' => PlanQuota::class,

The value is a number of bytes, null for unlimited, or an invokable class that receives the current tenant and returns a byte limit, or null.

php
use Illuminate\Database\Eloquent\Model;

class PlanQuota
{
    public function __invoke(?Model $tenant): ?int
    {
        return $tenant?->plan === 'pro' ? 50 * 1024 ** 3 : 5 * 1024 ** 3;
    }
}

Used space counts every file the tenant has, including files in the trash and previous versions. An upload that does not fit is refused. For chunked uploads the check runs when the first chunk arrives, before the file is stored. The library sidebar shows the storage used.

Private files ​

Tenancy separates tenants. Private files separate people inside a tenant.

A user can mark a file or folder as Only me. Private records are visible only to their uploader, and to users who pass the viewPrivate policy ability, for example admins. Turn the feature off with private_media => false. See Private Files and Authorization.

Commercial licence. One licence per production project. Terms · Privacy · Refunds