All packages
Campaigns for Laravel
Value objects
The facade, the manager and every store speak three plain PHP value objects — no Eloquent model involved, whichever store you use:
use RoundlyConsulting\Campaigns\Campaign;
use RoundlyConsulting\Campaigns\CampaignProgress;
use RoundlyConsulting\Campaigns\CampaignRecipient;
use RoundlyConsulting\Campaigns\Enums\CampaignStatus;
new Campaign(
uuid: 'e184d08f-5081-4fbb-9604-7a2460c3fb3a',
subject: 'Our spring collection is here',
content: '<p>Hello, the spring collection just landed.</p>',
fromName: 'Example Shop',
fromAddress: '[email protected]',
progress: new CampaignProgress, // optional — Created, every counter 0
startedAt: null, // optional ?Carbon
endedAt: null, // optional ?Carbon
batch: null, // optional Laravel batch id, set by prepare()
);
new CampaignRecipient(
uuid: '7f3eb754-709e-4837-b82a-49c83223eed6',
name: 'Ana Horvat',
reachableAt: '[email protected]', // an email address, phone number or any route
hasBeenProcessed: false, // optional
errorOccured: false, // optional
errorMessage: null, // optional
campaignUuid: null, // optional — set when the recipient is added to a campaign
);
new CampaignProgress(status: CampaignStatus::Created, sent: 0, pending: 0, total: 0, failed: 0);- Campaign — uuid, subject, content, fromName, fromAddress, progress, startedAt, endedAt and batch (the Laravel batch id).
- CampaignRecipient — uuid, name, reachableAt, hasBeenProcessed, errorOccured, errorMessage (null when there is no error) and campaignUuid (set once it is added to a campaign), plus belongsTo($campaignUuid).
- CampaignProgress — status, sent (delivered), failed, pending (no outcome yet) and total, plus percentage() (share delivered, 0–100), remaining(), isRunning() and isComplete().
The flag is spelled errorOccured (column error_occured) throughout the package — use that exact name.
Array form
toArray() returns JSON-ready arrays — dates as ISO 8601 strings, the status as its value, remaining and percentage included:
$campaign->toArray();
// [
// 'uuid' => 'e184d08f-5081-4fbb-9604-7a2460c3fb3a',
// 'subject' => 'Our spring collection is here',
// 'content' => '<p>Hello, the spring collection just landed.</p>',
// 'fromName' => 'Example Shop',
// 'fromAddress' => '[email protected]',
// 'progress' => [
// 'status' => 'Completed',
// 'sent' => 2,
// 'failed' => 0,
// 'pending' => 0,
// 'total' => 2,
// 'remaining' => 0,
// 'percentage' => 100.0,
// ],
// 'startedAt' => '2026-03-02T09:00:00+00:00',
// 'endedAt' => '2026-03-02T09:00:04+00:00',
// 'batch' => '9d3c6a1e-…',
// ]
$recipient->toArray();
// [
// 'uuid' => '7f3eb754-709e-4837-b82a-49c83223eed6',
// 'name' => 'Ana Horvat',
// 'reachableAt' => '[email protected]',
// 'hasBeenProcessed' => true,
// 'errorOccured' => false,
// 'errorMessage' => null,
// 'campaignUuid' => 'e184d08f-5081-4fbb-9604-7a2460c3fb3a',
// ]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 cryptoBy 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.