Nested relation form

Hi guys, is it possible to create form with nested relations?
// ClientResource.php

Forms\Components\Section::make()
->relationship('entity')
->schema([
// Fields on the entity model

Forms\Components\Section::make()
->relationship('address')
->schema([
// Fields on the address model
])
]),
// ClientResource.php

Forms\Components\Section::make()
->relationship('entity')
->schema([
// Fields on the entity model

Forms\Components\Section::make()
->relationship('address')
->schema([
// Fields on the address model
])
]),
On my ClientResource I have form like this. My entity model is created, but address model is not. I am not sure, if it is even possible.
12 Replies
Trauma Zombie
Trauma Zombie4mo ago
It doesn't create the address when creating, but it does when editing.
bernhard
bernhard4mo ago
Nested relations work. Just for the records if you think about nested resources read https://filamentphp.com/community/alexandersix-filament-what-to-expect-in-2024#nested-resources as well If you need extra logic, you can manipulate how the save process is treated with the saveRelationshipsUsing(callback) method But in general it should work without any extra logic!
Trauma Zombie
Trauma Zombie4mo ago
So, the code I posted above should work, and if it doesn't, is the problem somewhere on my end?
bernhard
bernhard4mo ago
Here is an working example:
class Country extends Model
{

public function capitalCity(): HasOne
{
return $this->hasOne(City::class);
}
}

class City extends Model
{
protected function country(): BelongsTo
{
return $this->belongsTo(Country::class);
}
}


class CountryResource extends Resource
{
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->required(),
Section::make("Capital")->schema([
TextInput::make("name")->required(),
TextInput::make("zip")->required()
])->relationship("capitalCity")
]);
}
}
class Country extends Model
{

public function capitalCity(): HasOne
{
return $this->hasOne(City::class);
}
}

class City extends Model
{
protected function country(): BelongsTo
{
return $this->belongsTo(Country::class);
}
}


class CountryResource extends Resource
{
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->required(),
Section::make("Capital")->schema([
TextInput::make("name")->required(),
TextInput::make("zip")->required()
])->relationship("capitalCity")
]);
}
}
This works
bernhard
bernhard4mo ago
Trauma Zombie
Trauma Zombie4mo ago
In my example Client belongsTo Entity that belongsTo Address, but when I am creating new client, it is created, also entity is created, but address not. When I edit that client and fill out also address fields, it is created now (only on edit). I have nested relation like this:
class ClientResource extends Resource
{
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make()
->relationship('entity')
->schema([
// Fields on the entity model

Forms\Components\Section::make()
->relationship('address')
->schema([
// Fields on the address model
])
]),
]);
}
}
class ClientResource extends Resource
{
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make()
->relationship('entity')
->schema([
// Fields on the entity model

Forms\Components\Section::make()
->relationship('address')
->schema([
// Fields on the address model
])
]),
]);
}
}
bernhard
bernhard4mo ago
ah. this is nested, nested 😄 so we are talking about $client->entity->address
Trauma Zombie
Trauma Zombie4mo ago
Right!
bernhard
bernhard4mo ago
Works in the same way:
class Country extends Model
{
public function capitalCity(): HasOne
{
return $this->hasOne(City::class);
}
}

class City extends Model
{
public function country(): BelongsTo
{
return $this->belongsTo(Country::class);
}

public function mainDistrict(): HasOne
{
return $this->hasOne(\App\Models\District::class);
}
}


class District extends Model
{
protected function city(): BelongsTo
{
return $this->belongsTo(\App\Models\City::class);
}
}

class CountryResource extends Resource
{
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->required(),

Section::make("Capital")->schema([
TextInput::make("name")->required(),
TextInput::make("zip")->required(),

Section::make("District")->schema([
TextInput::make("name")->required(),
])->relationship("mainDistrict")
])->relationship("capitalCity")
]);
}
}
class Country extends Model
{
public function capitalCity(): HasOne
{
return $this->hasOne(City::class);
}
}

class City extends Model
{
public function country(): BelongsTo
{
return $this->belongsTo(Country::class);
}

public function mainDistrict(): HasOne
{
return $this->hasOne(\App\Models\District::class);
}
}


class District extends Model
{
protected function city(): BelongsTo
{
return $this->belongsTo(\App\Models\City::class);
}
}

class CountryResource extends Resource
{
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->required(),

Section::make("Capital")->schema([
TextInput::make("name")->required(),
TextInput::make("zip")->required(),

Section::make("District")->schema([
TextInput::make("name")->required(),
])->relationship("mainDistrict")
])->relationship("capitalCity")
]);
}
}
bernhard
bernhard4mo ago
Trauma Zombie
Trauma Zombie4mo ago
Can you try it with just belongsTo relations? I am not sure if it matters, but maybe like this:
<?php

class Country extends Model
{
//
}

class City extends Model
{
public function district(): BelongsTo
{
return $this->belongsTo(District::class);
}
}

class District extends Model
{
public function country(): BelongsTo
{
return $this->belongsTo(Country::class);
}
}

class CityResource extends Resource
{
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->required(),

Section::make("District")
->relationship('district')
->schema([
TextInput::make("name")->required(),

Section::make("Country")
->relationship("country")
->schema([
TextInput::make("name")->required(),
])
])
]);
}
}
<?php

class Country extends Model
{
//
}

class City extends Model
{
public function district(): BelongsTo
{
return $this->belongsTo(District::class);
}
}

class District extends Model
{
public function country(): BelongsTo
{
return $this->belongsTo(Country::class);
}
}

class CityResource extends Resource
{
public static function form(Form $form): Form
{
return $form
->schema([
TextInput::make('name')
->required(),

Section::make("District")
->relationship('district')
->schema([
TextInput::make("name")->required(),

Section::make("Country")
->relationship("country")
->schema([
TextInput::make("name")->required(),
])
])
]);
}
}
bernhard
bernhard4mo ago
In my example, a country has ONE capitalCity of type City and a city has ONE mainDistrict of type District. So Country>City>District In your example, a city belongs to a district and a district belongs to a country. So Country>District>City