How to fetch and save different M:M relationships using Custom Page single edit/view form?

257 views Asked by At

In Filament, a Resource is based on a single parent model and every method I call on it (including relationship('relName', 'field name')) will look at that parent model to fetch things. I have a scenario where I need to fetch and save() multiple M:M relationships described in other models.

  • My models are Company, City, Prefecture with belongsToMany relationships defined on each

  • My tables are company_city and company_prefecture

  • My Custom Page is CompanyRegions

  • My app has basic Filament Multitenancy

  • By edit/view Custom Page I mean this

CompanyRegions Custom Page looks like this:

class CompanyRegions extends Page implements HasForms
{
    public function mount(): void {
        $tenant = Filament::getTenant();
        $companyID = $tenant->id;
        $companyRegions = auth()->user()->companies->find($companyID)->????;
        
        if($companyRegions === null) {
            $this->form->fill();
        } else {
            $this->form->fill(auth()->user()->companies->find($companyID)->regions->attributesToArray());
        }
    }

    public function form(Form $form): Form
    {
        return $form
            ->schema([
                Select::make('prefectures')
                    ->placeholder('Select prefectures you work in')
                    ->label('Prefectures')
                    ->options(Prefecture::all()->pluck('prefecture_ja', 'id'))
                    ->multiple()
                    ->searchable()
                    ->required(),
                Select::make('cities')
                    ->placeholder('Select cities you work in')
                    ->label('Cities')
                    ->options(City::all()->pluck('city_ja', 'id'))
                    ->multiple()
                    ->searchable()
                    ->required(),
            ])
            ->statePath('data');
    }
  protected function getFormActions(): array {
        return [
            Action::make('save')
                ->label(__('filament-panels::resources/pages/edit-record.form.actions.save.label'))
                ->submit('Save'),
        ];
    }

    public function save(): void {
        $tenant = Filament::getTenant();
        $data = $this->form->getState();
        $data['company_id'] = $tenant->id;
        $companyID = $tenant->id;

        $company = auth()->user()->companies->find($companyID);   
        $Entry = $company->???;

        if ($company->??? === null) {
            $Entry = new ModelsCompanyRegions;
            $Entry->fill($data);
            $Entry->save($data);
            
            Notification::make()
                ->success()
                ->title('Entry Created')
                ->send();
            } else {
                $Entry->update($data);
                Notification::make()
                ->success()
                ->title('Entry Updated)
                ->send();
           }
        }
}

I tried:

  1. Saving child models in $model2 $model3 variables and doing something like

    Select::make('Cities')->relationship($model2->cities, 'name'),
    
  2. Consulting ChatGPT. It ended up hallucinating a relatedModel method (I tested the hypothesis that it just might be deprecated by checking the official documentation for previous versions and via simple web search)

     Select::make('Cities')
                ->relationship('cities')
                **->relatedModel(City::class)** 
                ->searchable()
                ->sortable(),
    
     Select::make('Prefectures')
                ->relationship('prefectures')
                **->relatedModel(Prefecture::class)**
                ->searchable()
                ->sortable(),
    
  3. Asking around on other forums and trying to find a YouTube video or a Filament course that tackles an issue like mine.

And that's only fetching the data. For now I can only assume in order to save it I'll have to do something like this. And then populating it properly.

0

There are 0 answers