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

Primary contacts & ordering

Each owner has at most one primary contact per kind, always. With auto_primary on (the default) a kind that has contacts also keeps a primary: the first one added becomes it, and when the primary is deleted, synced away or moved to another kind, the next contact by position is promoted. Marking another contact primary demotes the previous one inside a database transaction:

$first = $user->addEmail('[email protected]');     // first email: primary automatically
$second = $user->addEmail('[email protected]', primary: true);

$first->fresh()->is_primary;     // false — demoted in the same transaction
$second->fresh()->is_primary;    // true

$phone = $user->addPhone('+421900000000');   // each kind keeps its own primary
$phone->is_primary;                          // true

Contacts::setPrimary($first);                // promote again; fires PrimaryContactChanged

Contacts::delete($first);                    // the primary leaves its kind...
$second->fresh()->is_primary;                // true — ...and the next by position takes over
  • Primaries are scoped by owner and raw kind — email, phone and each registered custom kind keep their own.
  • Ownerless contacts share one primary per kind among themselves.
  • PrimaryContactChanged fires with the new primary and the demoted one (or null) — for automatic promotions too.
  • With auto_primary off, nothing is promoted for you.
  • A restored primary comes back as a secondary if its kind promoted another contact meanwhile.
  • With require_owner_for_primary on, promoting an ownerless contact throws PrimaryContactConflict, and ownerless kinds are never auto-promoted.

Ordering

Every contact has a position within its kind. New contacts take the next free slot (starting at 0) unless ContactData sets one explicitly; sync() assigns positions by input order:

$user->addPhone('+421900000001');   // position 0
$user->addPhone('+421900000002');   // position 1 — next free slot within the kind

// Pin a position explicitly
$user->addContact(new ContactData(ContactType::Phone, '+421900000003', position: 0));

$user->contactsOfType(ContactType::Phone);            // ordered by position, then id
Contact::query()->forOwner($user)->ordered()->get();

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.