# [Usage](../../../usage.md) > Model Syncer

Use `ModelHelper::syncModel()` when a form (typically a [Repeater](../../components/forms/repeater.md) inside a [Form](../../components/forms/form.md)) submits a full child list and the database must match it exactly: new rows created, existing rows updated, missing rows deleted within a scope such as `processing_id`. For copy-instead-of-sync flows, see the comparison below.

Utility to **sync a set of rows** on an Eloquent model from an input array:
- **Creates** rows not yet existing (when primary key is `null`/missing)
- **Updates** rows that already exist
- **Deletes** rows in DB that are *not present* in the input array (only inside the given scope)

---

## Method

### `ModelHelper::syncModel($model, $array, $key = null, $keyValue = null, $callable = null)`

#### Arguments

- **`$model`** *(string|Model)*  
  The Eloquent model **class** (recommended) or a model instance.  
  Example: `\App\Models\Phase::class`


- **`$array`** *(array|Collection)*  
  List of records to sync. Each item is an associative array where:
    - key = column name
    - value = column value  
      Example item: `['id' => 610, 'processing_phase_id' => 101, 'notes' => null]`


- **`$key`** *(string|null)*  
  Optional “scope” column to limit which rows are considered for update/delete.  
  Example: `'processing_id'`


- **`$keyValue`** *(mixed)*  
  Value for the scope column.  
  Example: `123`  
  If `$key` is provided and `$keyValue` is `null`, the sync applies to rows where `$key` is `NULL`.


- **`$callable`** *(callable)*
  Callback to manipulate rows, can be used to handle relationship for the model.  
  Example:
  ```php
  ModelHelper::syncModel(
    Work::class,
    $data['works'],
    'order_id',
    $order->id,
    function (Work $work, array $row) {
      $workItem = $row['item_id'] ?? null;
  
      if ($workItem) {
          $work->items()->sync([(int) $workItem]);
      } else {
          $work->items()->detach();
      }
    }
  );
  ```

#### What it does

- Syncs only the rows matching the scope:
    - If `$key` is provided: only rows where `$key = $keyValue` (or `$key IS NULL` if `$keyValue` is null)
    - If `$key` is not provided: all rows in the model are considered

- Uses the model’s **primary key automatically** (no need to pass `'id'`).

---

## Output (optional)

The method **returns an array summary** you can use for logging/debugging, but you can also ignore it.

Returned structure:

```php
[
  'created'     => int,
  'updated'     => int,
  'deleted'     => int,
  'kept_ids'    => array,
  'deleted_ids' => array,
  'records'     => Collection
]
```

Meaning:
- **`created`**: number of new rows inserted
- **`updated`**: number of rows updated
- **`deleted`**: number of rows removed
- **`kept_ids`**: IDs that exist after the sync (created + updated)
- **`deleted_ids`**: IDs removed during the sync
- **`records`**: Records created and updated, minus deleted.

---

## Example

```php
use KFramework\Helpers\ModelHelper;
use App\Models\Phase;

$result = ModelHelper::syncModel(
    Phase::class,
    $payload['phases'] ?? [],
    'processing_id',
    $processingId
);

// Output is optional:
// dd($result);
```

## When to pick which

| Need | Use |
| ---- | --- |
| Reconcile a submitted list (create + update + delete in scope) | `ModelHelper::syncModel()` (this page) |
| Duplicate all rows from one scope value to another | [Records Cloner](records_cloner.md) |
| Deep-clone an in-memory object graph (components, arrays, closures) | [Universal Deep Cloner](universal_deep_cloner.md) |

Controller example with a repeater payload:

```php
// app/Http/Controllers/ProcessingController.php
public function update(Request $request, $id)
{
    $result = ModelHelper::syncModel(
        Phase::class,
        $request->input('phases', []),
        'processing_id',
        $id
    );

    return back()->with(['success' => "Synced: {$result['created']} created, {$result['updated']} updated, {$result['deleted']} deleted."]);
}
```

## See also

- [Usage](../../../usage.md)
- [Form component](../../components/forms/form.md) / [Repeater](../../components/forms/repeater.md)
- [Records Cloner](records_cloner.md) — copy scope instead of syncing it