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

Database persistence

InMemoryCampaignStore keeps campaigns in memory for the current request, console command or queued job — ideal for tests and create-and-send flows. For campaigns you look up, start or cancel later — delayed starts, dashboards, retries, audit — switch to the shipped database store with one line:

CAMPAIGNS_STORE='RoundlyConsulting\Campaigns\Stores\DatabaseCampaignStore'

Then publish and run the migrations (see Installation) — they are never auto-loaded. The database store behaves like the in-memory one — the same contract test suite runs against both — including keying recipients by campaign, so the same recipient added to two campaigns is kept in both.

Schema

TableColumnsModel
campaignsid, uuid (unique), subject, content (longText), from_name, from_address, status (indexed, default Created), sent, failed, pending, total, batch, started_at, ended_at, timestamps, deleted_atCampaignRecord
campaign_recipientsid, uuid, campaign_uuid (indexed), name, reachable_at, has_been_processed, error_occured, error_message, timestamps, deleted_at — unique (campaign_uuid, uuid)CampaignRecipientRecord

Models

The records are ordinary Eloquent models with soft deletes, so you can query them for dashboards and reports:

use RoundlyConsulting\Campaigns\Enums\CampaignStatus;
use RoundlyConsulting\Campaigns\Models\CampaignRecord;

$record = CampaignRecord::query()->where('uuid', $uuid)->firstOrFail();

$record->status;                                              // CampaignStatus (cast)
$record->recipients()->count();                               // HasMany CampaignRecipientRecord
$record->recipients()->where('error_occured', true)->get();   // failed recipients

CampaignRecord::query()->where('status', CampaignStatus::Processing)->get();

Both models ship factories for your tests:

use RoundlyConsulting\Campaigns\Models\CampaignRecipientRecord;
use RoundlyConsulting\Campaigns\Models\CampaignRecord;

$campaign = CampaignRecord::factory()->create();

CampaignRecipientRecord::factory()->count(3)->create([
    'campaign_uuid' => $campaign->uuid,
]);

Use real UUIDs

With the database store, campaign and recipient ids must be valid UUIDs. find() and findRecipient() return null for anything else without running a query, so a custom ->uuid() or CampaignRecipient id that isn’t a UUID can’t be found again. Generated ids are always valid.

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.