Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

oliverbusk's avatar

Filament - Tenant with an extra layer of ownership

Hi.

I have set up Filament with multitenancy, and I am using a classic "Team" model. I have one more layer below a team, that I call buckets:

A team can have many buckets, and a bucket can belong to one team.

Then, under a bucket, the user can upload many documents, meaning that: a bucket can have many documents, and a document can belong to one bucket.

Now, I have set up a new resource called DocumentResource, but I am simply unable to figure out how I can upload a simple document via a header action, since the document should belong to a bucket, and not to a team directly.

In my App panel, I have specified this:

tenant(Team::class, ownershipRelationship: 'bucket')

Then, on the DocumentResource I have set a relationship:

protected static ?string $model = Document::class;
protected static ?string $tenantRelationshipName = 'buckets';

Then, under the ListDocuments page, I would like to have the "Upload Document" modal:

protected function getHeaderActions(): array
{
    return [
       Actions\CreateAction::make()
                ->form([
                    FileUpload::make('name')
                        ->required()
                        ->storeFileNamesIn('original_filename')
                ])
    ];
}

When I upload, it fails, since Filament is looking for a team_id on the documents table. But there is none, only a bucket_id

0 likes
1 reply
LaryAI's avatar
Level 58

It seems like you're trying to upload a document and associate it with a bucket, which is then associated with a team. Since Filament is looking for a team_id on the documents table and you don't have one, you need to ensure that the document is associated with a bucket, which in turn is associated with the correct team.

Here's a solution that should help you achieve this. You need to modify the CreateAction to include a selection of the bucket that the document will be associated with. This way, you can ensure that the document is linked to the correct bucket and, by extension, the correct team.

First, make sure that your Document model has the correct relationship to the Bucket model:

class Document extends Model
{
    // ...

    public function bucket()
    {
        return $this->belongsTo(Bucket::class);
    }

    // ...
}

Then, in your DocumentResource, you need to modify the CreateAction to include a dropdown for selecting the bucket:

use Filament\Forms\Components\Select;
use Filament\Forms\Components\FileUpload;

// ...

protected function getHeaderActions(): array
{
    return [
        Actions\CreateAction::make()
            ->form([
                Select::make('bucket_id')
                    ->relationship('bucket', 'name') // Assuming 'name' is a field in your buckets table that you want to display
                    ->required(),
                FileUpload::make('document')
                    ->required()
                    ->storeFileNamesIn('original_filename'),
            ])
            ->action(function (array $data) {
                // Here you can handle the file upload and create the document
                $bucket = Bucket::findOrFail($data['bucket_id']);
                $document = new Document();
                $document->original_filename = $data['document']->getClientOriginalName();
                $document->path = $data['document']->store('documents'); // Adjust the path as needed
                $bucket->documents()->save($document);
            }),
    ];
}

Make sure to replace 'name' with the actual field you want to display from the buckets table.

This solution assumes that you have a buckets relationship method defined in your Team model that returns all the buckets associated with the team. Also, ensure that the bucket_id field is fillable in your Document model.

By adding a Select component for the bucket_id, you allow the user to choose which bucket the document should be associated with. The action method on the CreateAction is then responsible for handling the file upload and creating the new Document record with the correct bucket_id.

Remember to adjust the store method call to correctly save the file in your desired directory and to handle any validation or error checking as needed.

Please or to participate in this conversation.