Reusable Laravel package for storing contact form submissions with a status workflow, spam metadata, and soft deletes.
composer require turtlebytes/contact-formThe service provider and facade are auto-discovered by Laravel.
php artisan vendor:publish --provider="TurtleBytes\ContactForm\ContactFormServiceProvider" --tag="contact-form-config"php artisan vendor:publish --provider="TurtleBytes\ContactForm\ContactFormServiceProvider" --tag="laravel-migrations"
php artisan migrateuse TurtleBytes\ContactForm\ContactForm;
$submission = ContactForm::submit([
'name' => 'Jane Doe',
'email' => 'jane@example.com',
'phone' => '555-1234',
'subject' => 'Question about pricing',
'message' => 'Can you share your team plan options?',
'source' => 'website',
]);use TurtleBytes\ContactForm\Facades\ContactForm;
$submission = ContactForm::submit([
'name' => 'John Smith',
'email' => 'john@example.com',
'message' => 'I need support with onboarding.',
]);The package provides TurtleBytes\ContactForm\Models\ContactSubmission with:
- Status enum casting (
ContactStatus) - Spam tracking (
spam_score,spam_reasons,is_spam) - Lifecycle timestamps (
read_at,responded_at) - Soft deletes
name,email,phone,subject,messagestatus(new,read,responded,archived,spam)ip_address,user_agent,sourcespam_score,spam_reasons,is_spaminternal_notesread_at,responded_at,responded_by
ContactStatus values:
newreadrespondedarchivedspam
Workflow helpers on ContactSubmission:
$submission->markAsRead();
$submission->markAsResponded(userId: 42);
$submission->markAsSpam();
$submission->archive();
if ($submission->isNew()) {
// Handle unread submission
}Behavior notes:
markAsRead()only works when status isnew.markAsResponded()setsresponded_at, stores optionalresponded_by, and ensuresread_atis set.markAsSpam()sets both status andis_spam.
use TurtleBytes\ContactForm\Models\ContactSubmission;
$new = ContactSubmission::query()->new()->get();
$unresponded = ContactSubmission::query()->unresponded()->get();
$notSpam = ContactSubmission::query()->notSpam()->get();
$spam = ContactSubmission::query()->spam()->get();use TurtleBytes\ContactForm\ContactForm;
use TurtleBytes\SpamGuard\Facades\SpamGuard;
$spam = SpamGuard::check([
'email' => $request->string('email')->toString(),
'name' => $request->string('name')->toString(),
'message' => $request->string('message')->toString(),
'subject' => $request->string('subject')->toString(),
'ip_address' => $request->ip(),
]);
$submission = ContactForm::submit([
'name' => $request->string('name')->toString(),
'email' => $request->string('email')->toString(),
'subject' => $request->string('subject')->toString(),
'message' => $request->string('message')->toString(),
'ip_address' => $request->ip(),
'user_agent' => $request->userAgent(),
'source' => 'website',
'spam_score' => $spam->getScore(),
'spam_reasons' => $spam->getReasons(),
'is_spam' => $spam->isSpam(),
]);
if ($spam->isSpam()) {
$submission->markAsSpam();
}config/contact-form.php:
return [
'table' => 'contact_submissions',
];composer install
vendor/bin/pestMIT