# Relations

## `relation()`

### The form component supports all types of relationships!

Just add `->relation()` to any field and handle the data in the `saveFoo()` hook. Instead of writing default methods to support all Laravel relationships the `saveFoo()` hook gives you total freedom on how you want to manipulate the data before it is being saved. This way you can define any type of relationship you want.

### You are responsible for saving the data

The relationship fields are ignored in the default save method. If you do not handle it with the `saveFoo()` hook it will be as if it didn't exist in the form at all. The method is executed **after** the model is saved. Read more on [Manually saving data.](/tall-forms/concept/manually-saving-data.md)

Define the field

```php
Checkboxes::make('Attach to Events', 'event_ids')//make sure that the name doesn't collide with a model property
    ->options($this->events)//if using checkboxes read the documentation about integer values
    ->relation() //tell the component that this field is a relationship
    ->rules('nullable|array|exists:events,id'),
```

### saveFoo() - save the data

You can omit `FormData` in the method name, if it is an array like `form_data.organization.name` the method name becomes `saveOrganizationName()`

**The data is accessed via** `data_get($relationship_data, 'foo')` or the fields `name` property, like `$this->foo`, depending on how you setup your form Add the `saveFoo()` method to your component. The relationship will be passed with the same `name` as the field.

Example with a field named 'event\_ids'

```php
protected function saveEventIds($validated_value)
{
    // the field data is accessed via the fields name property
    $selected_events = $validated_value;
    //or depending on your form setup
    $selected_events = $this->event_ids;
    // save the data
    $this->model->...
}
```

## `BelongsTo` relationship

You usually **don't have to use the `relation()` option** for a BelongsTo relationship because you can use a simple `select` field.

Example BelongsTo, no->relation() needed.

```php
//Populate a property in the components mount() method to setup the options for the select.
$this->belongsToOptions = //some query()->toArray() as [$key => $value]

//in the fields() method
Select::make('Belongs To', 'some_model_id')
  ->options($this->belongsToOptions)
  ->rules([
    'required',
     'exists:some-table,id',
     Rule::in(array_values($this->belongsToOptions))
  ])
->placeholder("Select a model"),
```

## Auto populate the relationship field if there is only one value

[See the `autoSelectSingleArrayValue()` docs ->](https://github.com/tanthammar/tall-forms/wiki/Methods#autoselectsinglearrayvaluestring-arrayname-string-field)

## ManyToMany relationship

In this `edit` form example a `Location` can be related to many `Events`.

### Existing relations and options

We will use a **fake model attribute**, `event_ids`, that does not exist as a column in the database. We use the `beforeFormProperties()` method to set existing relations as an appended attribute before `form_data` is set.

We also need to get available `events` to use as options for the checkboxes.

```php
protected function beforeFormProperties()
{
    // get existing relations, read the checkboxes docs about integer values
    $this->model->event_ids = array_map('strval', optional($this->model->events)->pluck('id')->all());
    
    // set the checkboxes options
    $this->events = Event::query()->teamFilter()->select('id', 'name')->get()->pluck('id', 'name')->all();
}
```

### Define the field

We will use `checkboxes` to display available events in the form. We also check if there are any available Events before adding the field to the form. Add the `relation()` property to the field.

```php
protected function fields()
{
    return [

        filled($this->events) ? Checkboxes::make('Attach to Events', 'event_ids')
            ->options($this->events)
            ->relation()
            ->placeholder(trans('global.select').' '.trans('crud.event.title_singular'))
            ->rules('nullable|array|exists:events,id') : null,
    ];
}
```

### Save the data

Add the `saveFoo()` to the component.

```php
protected function saveEventIds($validated_value)
{
    //get the options that the user selected via the field name
    $selected_events = $validated_value;
    
    //if the user unselected all available options it means we have to detach any existing relations
    if (blank($selected_events)) {
        $this->model->events()->detach(); //detach all existing relations
    } else {
        //in this example we scoped the events to the users current team, so we check which events the user is allowed to attach
        //this is also a good example on how to validate the submitted data
        $allowed_to_sync = filled($selected_events) ? array_intersect($selected_events, array_values($this->events)) : [];
        if (filled($allowed_to_sync)) $this->model->events()->sync($selected_events);
    }
}
```

## HasMany

### Repeater field

You can use a `Repeater` field and map the relationship query to an array. This might not be a good idea if you have a lot of related items.

```php
protected function beforeFormProperties() {
    $this->model->temporary_prop = $this->model->bedrooms()->all()->map()->toArray();
}

//fields()
Repeater::make('Bedrooms', 'temporary_prop')->fields([...])->relation();

//saveFoo
protected function saveTemporaryProp($validated_data);
{ 
       foreach($validated_data as $bedroom) { 
           data_set($bedroom, 'parent_id', $this->model->id);
           $bedroom = Bedroom::firstOrCreate(
                     ['id' => $bedroom['id']],
                     Arr::except($bedroom, ['id']);
            );
       }
}
```

### Child components

You can have separate forms for each child. Maybe with the "[Without buttons](/tall-forms/form/form-types/without-buttons.md)" form type (submit on keydown enter) or keep just the save button.

Something like this, in the parent view:

```php
{{-- blank form on top to create new items --}}
{{-- clear the form on submit, and emit $refresh to the other forms, for the children to become visible --}}
<livewire:forms.add-bedroom />

{{-- loop hasMany items --}}
@foreach($bedrooms as $bedroom)
  <livewire:forms.bedroom :bedroom="$bedroom"/>
@endforeach
```

### Inline edit

You could also have a `div` with a `click` event that hides or shows each child form. Like an "inline edit" thing. It depends on how many related items you will handle att the same time, or use form type "[As Modal](/tall-forms/form/form-types/modal.md)", to load the child model on a click event.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tina-hammar.gitbook.io/tall-forms/field/relationships.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
