NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Forms for Laravel

Resolvers & autofill

A resolver controls how a field’s value is read from the request (toStorable) and read back from storage (fromStorage). The package ships DefaultResolver and MediaFileResolver. Implement RoundlyConsulting\Forms\Resolvers\Resolver — its constructor receives the Field — and map it to a field type in config/forms.php:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use RoundlyConsulting\Forms\Models\Field;
use RoundlyConsulting\Forms\Resolvers\Resolver;

class CheckboxResolver implements Resolver
{
    public function __construct(private Field $field) {}

    public function toStorable(Request $request, ?Model $sender = null): array
    {
        return ['value' => $request->boolean($this->field->path())];
    }

    public function fromStorage(?Model $sender = null): mixed
    {
        return $this->field->submissions()
            ->where('field_id', $this->field->getKey())
            ->value('value')['value'] ?? null;
    }
}
// config/forms.php
'fields' => [
    'default' => \RoundlyConsulting\Forms\Resolvers\DefaultResolver::class,
    'checkbox' => \App\Forms\CheckboxResolver::class,
],

Return the value wrapped as ['value' => …] — that is the shape typedValue() and the submissions reader unwrap. A type without its own mapping falls back to fields.default; if neither exists, UnresolvableFieldException is thrown.

Resolvers that need the stored row

A resolver that needs the persisted submission row before it can store its value additionally implements AttachesToSubmission, whose attach() runs after the row is created, inside the same transaction, and whose restoreUpload() hands back a temporary copy of the stored file (or null) so finalizing a draft can validate it against the field’s rules. MediaFileResolver is the reference implementation:

// RoundlyConsulting\Forms\Resolvers\AttachesToSubmission
public function attach(Submission $submission, Request $request, ?Model $sender = null): void;

// A temporary copy of the stored file (or null), so finalizing a draft can validate it
// against the field's rules — the caller deletes the copy once validation has run.
public function restoreUpload(Submission $submission): ?UploadedFile;

// How MediaFileResolver implements attach() — the row exists, so it can own media:
public function attach(Submission $submission, Request $request, ?Model $sender = null): void
{
    $file = $request->file($this->field->path());

    if (! $file instanceof UploadedFile) {
        return;
    }

    $media = $submission->addMedia($file)->toBucket($submission->attachmentBucket());

    $submission->update(['value' => ['value' => $media->uuid]]);
}

Autofill

Set a field’s autofill to a class implementing RoundlyConsulting\Forms\Autofill\Autofill to compute a default value on the fly:

use RoundlyConsulting\Forms\Autofill\Autofill;
use RoundlyConsulting\Forms\Models\Field;

class CurrentUserEmail implements Autofill
{
    public function fill(Field $field): mixed
    {
        return auth()->user()?->email;
    }
}

// $field->getAutofillValue() resolves the class and returns its fill() result,
// or the raw `autofill` string when it isn't an Autofill class — such a class is never built.
$g->field('email', 'Email')->email()->autofill(CurrentUserEmail::class);

$field->getAutofillValue(); // '[email protected]' for the signed-in user

Autofill classes are resolved through the container, so constructor injection works. The column is data: a class it names that isn’t an Autofill is never built — its string is returned as-is. FieldResource exposes the resolved value to your frontend.

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

By donating, you agree to our donation terms.

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.