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

jcc5018's avatar

Bit confused on structuring related data

I thought there was some sort of function where if I write something like 'addresses.country.name' it would configure the relationships between the various models. I am probably confusing a concept, but I'm not sure the proper way to handle this. Thanks for any help

I have a groupResource that can have many addresses.

Group Model:
  public function addresses()
    {
        return $this->morphMany(Address::class, 'addressable');
    }

Address Model:

 public function state(): BelongsTo
    {
        return $this->belongsTo(State::class, 'state_id');
    }

    public function country(): BelongsTo
    {
        return $this->belongsTo(Country::class, 'country_id');
    }


    //    protected $appends = ['address'];

    public function city(): BelongsTo
    {
        return $this->belongsTo(City::class, 'city_id');
    }

The address table also has city_id, state_id and country_id with their respective tables.

So what is the proper way to structure this so that the data is saved as an address connected to the group:

Also, with cities, can this be configured where the user inputs the city manually, but if it matches an existing city within the specified state, suggest and use that.

This setup will be a repeater, but that's not set up yet


Section::make('Addresses')->schema([
                                        TextInput::make('addresses.title')
                                                 ->label('Location Name'),
                                        TextInput::make('addresses.address_1')
                                                 ->label('Address Line 1'),
                                        TextInput::make('addresses.address_2')
                                                 ->label('Address Line 2'),
                                        Select::make('addresses.country_id')
                                              ->label('Country')
                                              ->options(Country::all()
                                                               ->pluck('name',
                                                                   'id'))
                                              ->preload()
                                              ->live()
                                              ->searchable(),
                                        Select::make('addresses.state_id')
                                              ->label('State')
                                              ->options(fn(Get $get
                                              ): Collection => State::query()
                                                                    ->where('country_id',
                                                                        $get('addresses.country_id'))
                                                                    ->pluck('name',
                                                                        'id'))
                                              ->preload()
                                              ->searchable(),
                                        TextInput::make('addresses.city_id')
                                                 ->label('City'),

                                        TextInput::make('addresses.zip')
                                                 ->label('Zip Code'),


                                    ]),

Address table fields:

'title', 'address_1', 'address_2', 'city_id', 'city', 'state_id', 'country_id', 'postal_code', 'type', 'addressable_type', 'addressable_id',

0 likes
3 replies
LaryAI's avatar
Level 58

It seems like you're trying to set up a form to handle addresses related to a Group model, and you want to ensure that the relationships between addresses, cities, states, and countries are properly managed. Here's how you can structure your models and handle the form inputs to ensure everything is connected correctly.

Model Setup

You already have the relationships set up in your models, which is great. Ensure that each model correctly defines its relationships:

// Group Model
public function addresses()
{
    return $this->morphMany(Address::class, 'addressable');
}

// Address Model
public function country(): BelongsTo
{
    return $this->belongsTo(Country::class, 'country_id');
}

public function state(): BelongsTo
{
    return $this->belongsTo(State::class, 'state_id');
}

public function city(): BelongsTo
{
    return $this->belongsTo(City::class, 'city_id');
}

Form Handling

When handling the form submission, you need to ensure that the address data is correctly associated with the Group. Here's a basic way to handle the form submission and save the data:

public function store(Request $request)
{
    $group = Group::find($request->group_id); // Assuming you pass the group ID

    $address = new Address([
        'title' => $request->input('addresses.title'),
        'address_1' => $request->input('addresses.address_1'),
        'address_2' => $request->input('addresses.address_2'),
        'city_id' => $request->input('addresses.city_id'),
        'state_id' => $request->input('addresses.state_id'),
        'country_id' => $request->input('addresses.country_id'),
        'postal_code' => $request->input('addresses.zip'),
    ]);

    $group->addresses()->save($address);

    return redirect()->back()->with('success', 'Address added successfully!');
}

Handling City Input

For handling city input where the city is manually entered but should match an existing city in the database if available, you can modify the city handling like this:

$cityName = $request->input('addresses.city');
$stateId = $request->input('addresses.state_id');

$city = City::firstOrCreate([
    'name' => $cityName,
    'state_id' => $stateId
]);

$address->city_id = $city->id;

This code checks if a city with the given name and state ID exists, and if not, it creates a new city. This ensures that if a city is already in the database, it won't create a duplicate.

Conclusion

With this setup, you should be able to handle the creation of addresses linked to a group, with proper relationships to cities, states, and countries. Make sure to validate the inputs to ensure data integrity.

jcc5018's avatar

@LaryAI I dont think this helps with the filament structure.

Im starting to think filament is not the best idea

jcc5018's avatar
jcc5018
OP
Best Answer
Level 8

The chat system provided a better response, though im still confused about the dot notation that i know I've seen somewhere that is supposed to get a relation value

Repeater::make('addresses')
                                            ->relationship('addresses') // Ensure this is the correct relationship method name
                                            ->schema([
                                            TextInput::make('title')
                                                     ->label('Location Name'),
                                            TextInput::make('address_1')
                                                     ->label('Address Line 1'),
                                            TextInput::make('address_2')
                                                     ->label('Address Line 2'),
                                            Select::make('country_id')
                                                  ->label('Country')
                                                  ->options(Country::all()
                                                                   ->pluck('name',
                                                                       'id'))
                                                  ->reactive()
                                                  ->afterStateUpdated(fn(
                                                      $state,
                                                      $set
                                                  ) => $set('state_id', null)),
                                            // Reset state when country changes
                                            Select::make('state_id')
                                                  ->label('State')
                                                  ->options(fn($get
                                                  ) => State::where('country_id',
                                                      $get('country_id'))
                                                            ->pluck('name',
                                                                'id'))
                                                  ->reactive()
                                                  ->afterStateUpdated(fn(
                                                      $state,
                                                      $set
                                                  ) => $set('city_id', null)),
                                            // Reset city when state changes
                                            Select::make('city_id')
                                                  ->label('City')
                                                  ->options(fn($get
                                                  ) => City::where('state_id',
                                                      $get('state_id'))
                                                           ->pluck('name',
                                                               'id')),

                                            TextInput::make('postal_code')
                                                     ->label('Zip Code'),
                                        ]),

Please or to participate in this conversation.