Skip to main content

Temporary Entities

Qore\Next\System\Models\TemporaryEntity stores nested form data before it is attached to a real model.

The main user is RepeaterField: a repeater row can be created, edited and upload files before the parent resource form has been saved.

Why It Exists

Nested form rows need an identity before the parent model exists. TemporaryEntity gives each row a UUID and a payload so the frontend can keep editing rows while the parent form is still in progress.

It also implements ModelWithFiles, so nested FileFields can attach uploaded files to a temporary row first.

What The Model Stores

TemporaryEntity stores:

  • uuid as the stable frontend row identity;
  • name as the repeater field name;
  • payload as the nested field values;
  • user_id for the user creating the row;
  • entity_type and entity_id after the parent model is saved;
  • delete_at for rows that are temporary and can be cleaned up.

The payload and delete_at attributes are cast to array and datetime.

Repeater Flow

When a repeater form opens, RepeaterField returns a nested FormNode for the row fields.

When the row form submits:

  1. The nested form validates the row payload.
  2. Qore updates an existing TemporaryEntity by UUID or creates a new one.
  3. Nested file fields lazily attach files to the temporary entity.
  4. The response returns TemporaryEntityJsonResource with the row UUID and payload.

When the parent model is saved:

  1. RepeaterField receives the submitted row UUIDs and payloads.
  2. Existing rows for the parent that are no longer submitted are deleted.
  3. Submitted rows are updated with the final payload.
  4. entity_type, entity_id and delete_at are updated so the rows belong to the real model.

Using The Value

The value of a repeater field is an array of temporary entities:

RepeaterField::make('contacts')
->setFields(function (Form $form) {
return [
TextField::make('name')->setRules(fn () => ['required', 'string']),
EmailField::make('email')->setRules(fn () => ['nullable', 'email']),
];
});

If those rows should become application-specific models, add a lazy mutator that reads the submitted repeater value after the parent model exists.

Cleanup

Temporary rows use delete_at for abandoned data. Rows become permanent when the parent model save associates them and clears delete_at.

If you add custom temporary workflows, follow the same pattern: set delete_at while the entity is unattached, and clear it only when the data belongs to a real model.