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

Campaign status

Every campaign moves through the CampaignStatus enum. Each transition fires a lifecycle event — but only when the status actually changes, so repeated calls never re-dispatch:

StatusReached whenEvent
CreatedThe default status of a new Campaign object.—
Pendingprepare() opened the job batch and stored the recipients; nothing is sent yet.CampaignPrepared
Processingstart() won the move from Pending and queued the recipient jobs; startedAt is set.CampaignStarted
CompletedEvery delivery job ran — some may have failed — or there was nobody to send to.CampaignCompleted
FailedEvery delivery job ran and not one delivery got through.CampaignFailed
Canceledcancel() cancelled the batch.CampaignCancelled

startedAt is set on the first switch to Processing, endedAt on the first terminal status. Completed, Failed and Canceled are terminal and final — a cancelled campaign stays Canceled when its batch finishes. Every transition is a compare-and-set on the stored status, so two processes racing one campaign never both move it.

Enum helpers

CampaignStatus is string-backed — each value equals its case name — and adds isTerminal() on top of the enums-for-laravel Helpers trait:

use RoundlyConsulting\Campaigns\Enums\CampaignStatus;

CampaignStatus::Processing->isTerminal();   // false
CampaignStatus::Canceled->isTerminal();     // true — Completed, Failed and Canceled are terminal

CampaignStatus::values();                   // Collection of 'Created', 'Pending', 'Processing', …
CampaignStatus::toOptions();                // Collection: ['Created' => 'Created', …] for selects
CampaignStatus::validationRule();           // 'in:Created,Pending,Processing,Completed,Failed,Canceled'
CampaignStatus::tryFromName('Pending');     // CampaignStatus::Pending
CampaignStatus::hasValue('Failed');         // true
CampaignStatus::Completed->label();         // 'Completed'

The trait also brings labels(), options(), readable() and the other case lookups such as tryFromName() and hasValue(). validationRule() drops straight into a form request when you filter campaigns by status.

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.