---
title: "Models, scopes & soft deletes — Forms for Laravel | Roundly"
description: "Query scopes for public, active and expired forms, recoverable soft deletes, and swapping any model for your own subclass."
url: https://roundly-consulting.com/open-source/docs/forms-for-laravel/models-scopes
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Forms for Laravel](https://roundly-consulting.com/open-source/docs/forms-for-laravel.md)

# Models, scopes & soft deletes

Form ships query scopes: public(), active() (no expiry or not yet expired), expired() and forKey($key). Group and Field expose ordered():

```php
use RoundlyConsulting\Forms\Models\Form;

$openForms = Form::query()->public()->active()->get();

Form::query()->expired()->get();              // expires_at in the past
Form::query()->forKey('contact')->first();    // by key

$form->groups()->ordered()->get();            // Group::ordered() — by `order`
$group->fields()->ordered()->get();           // Field::ordered() — by `order`
```

Submission rows add final() and draft() scopes, and FormSubmission adds pendingApproval().

## Soft deletes

All models use soft deletes — deleting a form keeps its rows and submissions in the database, recoverable with restore() and queryable with withTrashed(). Deletes are not cascaded, so soft-deleting a form leaves its groups, fields and submissions intact, and past submissions stay readable after a field, group or form they answered is soft-deleted.

A soft-deleted form, group or field gives its key up: a new form can take the key (a new group or field theirs, within the same form or group), and forms:sync / Forms::update() re-create it. Restoring a record takes the key back — and fails with a unique-constraint violation while a live record holds it:

```php
$form->delete();   // soft delete — groups, fields and submissions stay intact, the key is freed

// A new form can take the freed key; forms:sync and Forms::update() re-create it.
// Restoring takes the key back — and fails while a live form holds it.
Form::withTrashed()->forKey('contact')->first()?->restore();

// Force-deleting a submission row also purges its attachment media.
$row->forceDelete();
```

## Swapping models

Point any forms.models entry at your own class to add columns, relations or scopes. The override must be the package model or extend it — any other class throws an InvalidConfigurationException naming the key instead of silently falling back to the package model:

```php
// config/forms.php
'models' => [
    'form' => \App\Models\Form::class,
    // ...
],

// app/Models/Form.php — must extend the package model
namespace App\Models;

class Form extends \RoundlyConsulting\Forms\Models\Form
{
    // extra columns, relations, scopes
}
```

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/forms-for-laravel.md)
