F
Filament10mo ago
Jeff

Add/Set Value of Tenant ID when saving

I have the following to allow creation of a "type" when filling in a form. The type is to be tied to the current tenant when saved but the ID isn't passed through, and I don't know how to inject it on SAVE. The mutateFormDataBeforeCreate doesn't seem to work in this context. I'm sure it's simple, but I can't find it. The error complains the field doesn't have a default value - which makes sense.
->createOptionForm([
Forms\Components\TextInput::make('typename')
->required()
->maxLength(255),
Forms\Components\TextInput::make('color')
->required()
->default('#e5e7eb'),
Forms\Components\TextInput::make('display_order')
->required()
->numeric()
->default(999),
])
->createOptionForm([
Forms\Components\TextInput::make('typename')
->required()
->maxLength(255),
Forms\Components\TextInput::make('color')
->required()
->default('#e5e7eb'),
Forms\Components\TextInput::make('display_order')
->required()
->numeric()
->default(999),
])
Solution:
I have a simple usage in one of my apps that just looks like this ... ```php ->createOptionUsing(function ($data) { return Order::create($data)->id;...
Jump to solution
10 Replies
DrByte
DrByte10mo ago
When using the Create page of a Resource within a Panel, I am successfully using mutateFormDataBeforeCreate (This is NOT a tenant-aware application in this case):
/**
* associate with current user and show before saving
* nb: user_id will be null when created by another guard
*/
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth('web')->id();
$data['show_id'] = Show::currentShow()->id;

return $data;
}
/**
* associate with current user and show before saving
* nb: user_id will be null when created by another guard
*/
protected function mutateFormDataBeforeCreate(array $data): array
{
$data['user_id'] = auth('web')->id();
$data['show_id'] = Show::currentShow()->id;

return $data;
}
I would expect similar to work for setting tenant data.
cheesegrits
cheesegrits10mo ago
Could you not add it as a hidden field on your createOptionForm(), and default it there to the current tenant?
Jeff
Jeff10mo ago
Yeah, the documentation says basically the same thing. As I read the error more closesly, I notice that the team_id field is not part of the insert, even though it's most definitely part of the db schema. Yep - Totally could, but it's subject to user manipulation then.
cheesegrits
cheesegrits10mo ago
If all else fails, you can always override the create option action and save the record yourself, inserting the tenant id there. Can't remember if I've got example code, hang on .. Yeah, you should be able to use createOptionUsing(), which take the $data array from your createOptionForm ... something like ...
->createOptionUsing(function ($data) {
return YourThing::create(array_merge($data, ['team_id' => Filament::getTenant()->id)->id;
}),
->createOptionUsing(function ($data) {
return YourThing::create(array_merge($data, ['team_id' => Filament::getTenant()->id)->id;
}),
I'm guessing at the Filament::getTenant()->id part, might need a ->getId() accessor or something, but you get the idea.
Jeff
Jeff10mo ago
Looks about right - I'll give this a try. The hidden field "works" but I don't like it. Thanks for your help!
Solution
cheesegrits
cheesegrits10mo ago
I have a simple usage in one of my apps that just looks like this ...
->createOptionUsing(function ($data) {
return Order::create($data)->id;
}),
->createOptionUsing(function ($data) {
return Order::create($data)->id;
}),
cheesegrits
cheesegrits10mo ago
You just have to return the 'id' (or whatever your PK is) so Filament knows how to select it in the dropdown after creating. And yes, absolutely better than using a hidden field, which as you say is open to abuse. I also can't help but feel this should be something Filament should have an option to take care of. I may look at PR'ing that.
Jeff
Jeff10mo ago
Got me on the right track anyway! Which is important. Such a silly thing to get stuck on.
cheesegrits
cheesegrits10mo ago
It's always the silly / "easy" things we get stuck on. I'm working on PR'ing a tenancy panel into the Demo app, so I have something to reference and test in when answering tenancy support issues. I don't have any multi-tenant apps of my own. So I'm also trying to add little quality of life fixes for associated functionality, and this is a good case.
Jeff
Jeff10mo ago
Amazing - Your example worked perfectly.