Forms - v1.0.0-beta1
Jobs
Queue job classes for ArtisanPack UI Forms.
SendFormNotification
Sends email notifications for form submissions.
Usage
use ArtisanPackUI\Forms\Jobs\SendFormNotification;
use ArtisanPackUI\Forms\Models\FormNotification;
use ArtisanPackUI\Forms\Models\FormSubmission;
// Dispatch the job
SendFormNotification::dispatch($notification, $submission);
// Dispatch to specific queue
SendFormNotification::dispatch($notification, $submission)
->onQueue('notifications');
Job Properties
| Property | Type | Description |
|---|---|---|
$notification |
FormNotification | Notification configuration |
$submission |
FormSubmission | Form submission data |
Configuration
Configure the notification queue in config/artisanpack/forms.php:
'notifications' => [
'queue' => 'notifications',
],
Handling Failures
The job implements retry logic:
public int $tries = 3;
public int $backoff = 60; // seconds
public function failed(Throwable $exception): void
{
Log::error('Failed to send form notification', [
'notification_id' => $this->notification->id,
'submission_id' => $this->submission->id,
'error' => $exception->getMessage(),
]);
}
Testing
use ArtisanPackUI\Forms\Jobs\SendFormNotification;
use Illuminate\Support\Facades\Queue;
test('notification job is dispatched', function () {
Queue::fake();
// Trigger form submission...
Queue::assertPushed(SendFormNotification::class, function ($job) {
return $job->notification->id === 1;
});
});
SendWebhook
Sends webhook payloads to external services.
Usage
use ArtisanPackUI\Forms\Jobs\SendWebhook;
use ArtisanPackUI\Forms\Models\Form;
use ArtisanPackUI\Forms\Models\FormSubmission;
// Dispatch webhook
SendWebhook::dispatch($form, $submission, $webhookUrl, $secret);
Job Properties
| Property | Type | Description |
|---|---|---|
$form |
Form | Form model |
$submission |
FormSubmission | Submission data |
$url |
string | Webhook endpoint URL |
$secret |
string|null | Secret for signing |
Payload Structure
{
"event": "form.submitted",
"timestamp": "2024-01-15T10:30:00Z",
"form": {
"id": 1,
"name": "Contact Form",
"slug": "contact"
},
"submission": {
"id": 123,
"submission_number": "FORM-2024-0001",
"data": {
"name": "John Doe",
"email": "john@example.com",
"message": "Hello!"
},
"submitted_at": "2024-01-15T10:30:00Z"
}
}
Request Signing
Webhooks are signed with HMAC-SHA256:
$signature = hash_hmac('sha256', $payload, $secret);
// Sent as X-Signature header
Verify in your receiving endpoint:
$expectedSignature = hash_hmac('sha256', $request->getContent(), $secret);
$receivedSignature = $request->header('X-Signature');
if (!hash_equals($expectedSignature, $receivedSignature)) {
abort(401, 'Invalid signature');
}
Configuration
// config/artisanpack/forms.php
'webhooks' => [
'enabled' => true,
'url' => env('FORMS_WEBHOOK_URL'),
'secret' => env('FORMS_WEBHOOK_SECRET'),
'queue' => 'webhooks',
'timeout' => 30,
'retry_times' => 3,
'retry_backoff' => [10, 60, 300], // seconds
],
Retry Logic
The job implements exponential backoff:
public int $tries = 3;
public function backoff(): array
{
return config('artisanpack.forms.webhooks.retry_backoff', [10, 60, 300]);
}
Customizing Payload
Use filters to modify the webhook payload:
use function addFilter;
addFilter('forms.webhook_payload', function ($payload, $form, $submission) {
// Add custom data
$payload['custom'] = [
'source' => 'website',
'campaign' => $submission->getMetadata('utm_campaign'),
];
// Remove sensitive data
unset($payload['submission']['data']['password']);
return $payload;
});
Privacy Options
Configure what's included in webhooks:
// config/artisanpack/forms.php
'privacy' => [
'include_ip_address' => false, // Exclude IP from webhooks
'include_user_agent' => false, // Exclude user agent
],
Handling Failures
public function failed(Throwable $exception): void
{
Log::error('Webhook delivery failed', [
'form_id' => $this->form->id,
'submission_id' => $this->submission->id,
'url' => $this->url,
'error' => $exception->getMessage(),
]);
// Optionally notify admin
Notification::send(
Admin::all(),
new WebhookFailedNotification($this->form, $exception)
);
}
Testing
use ArtisanPackUI\Forms\Jobs\SendWebhook;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Queue;
test('webhook is dispatched on submission', function () {
Queue::fake();
// Configure webhook
config(['artisanpack.forms.webhooks.enabled' => true]);
config(['artisanpack.forms.webhooks.url' => 'https://example.com/webhook']);
// Submit form...
Queue::assertPushed(SendWebhook::class);
});
test('webhook sends correct payload', function () {
Http::fake();
$job = new SendWebhook($form, $submission, 'https://example.com/webhook', 'secret');
$job->handle();
Http::assertSent(function ($request) {
return $request->url() === 'https://example.com/webhook'
&& $request->hasHeader('X-Signature')
&& $request['event'] === 'form.submitted';
});
});
Running Queue Workers
Ensure queue workers are running for jobs to process:
# Single worker
php artisan queue:work
# Specific queues
php artisan queue:work --queue=notifications,webhooks
# With Supervisor (production)
# /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
command=php /var/www/html/artisan queue:work --queue=notifications,webhooks
Next Steps
- Events - Event documentation
- Webhooks - Webhook configuration
- Notifications - Email notifications