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

Contact kinds & normalization

RoundlyConsulting\Contacts\Enums\ContactType is a backed string enum with six kinds: Email, Phone, Address, Url, Social and Custom. Each kind drives normalization, validation, a translatable label and an icon name:

KindNormalizationDefault rulesLabelIcon
emailLower-cased and trimmed.required, string, emailEmailenvelope
phoneSeparators stripped, leading + kept, 00 read as +, a (0) after the country code dropped; default_country_code replaces a national number’s trunk 0.required, string, regex:/^\+?[1-9]\d{6,14}$/Phonephone
addressTrimmed.required, stringAddressmap-pin
urlhttps:// prepended when no scheme is present.required, string, urlWebsiteglobe-alt
socialTrimmed.required, stringSocialat-symbol
customTrimmed.required, stringOtheridentification

Normalization

Normalization is pure PHP with no external libraries. It runs before validation on every add, update and sync, so the same number is never stored five different ways:

use RoundlyConsulting\Contacts\Enums\ContactType;

ContactType::Email->normalize(' [email protected] ');  // '[email protected]'
ContactType::Phone->normalize('+421 (900) 000-000');      // '+421900000000'
ContactType::Phone->normalize('+44 (0)20 7946 0000');     // '+442079460000' — the (0) is dropped
ContactType::Phone->normalize('00421 900 123 456');       // '+421900123456' — 00 reads as +
ContactType::Phone->normalize('0900 123 456');            // '0900123456' — bare digits
// ...or '+421900123456' with CONTACTS_DEFAULT_COUNTRY_CODE=421 (trunk 0 replaced)
ContactType::Url->normalize('example.com');               // 'https://example.com'
ContactType::Url->normalize('ftp://files.example.com');   // unchanged — has a scheme
ContactType::Social->normalize('  @janedoe ');            // '@janedoe'

Phone normalization is best-effort E.164. A leading 00 is read as +, and a (0) after the country code is dropped. With default_country_code set (for example 421), a national number gets it in place of its trunk 0 — 0900 123 456 becomes +421900123456; Italy and San Marino keep the 0, as their numbers do. Without it, a national number keeps its bare digits.

Rules always run on the normalized value — what gets stored — and every value is capped at 255 characters, the value column’s length. A value that fails either throws InvalidContactValue before anything is written.

Labels, icons and rules

ContactType::Phone->label();              // 'Phone' — config, then translation, then value
ContactType::Phone->icon();               // 'phone'
ContactType::Phone->validationRules();    // ['required', 'string', 'regex:/^\+?[1-9]\d{6,14}$/']
ContactType::Phone->rules();              // ['required', 'string', new ValidContactValue(ContactType::Phone)]
ContactType::fromValueOrCustom('email');  // ContactType::Email
ContactType::fromValueOrCustom('fax');    // ContactType::Custom

label() resolves in order: a label set in contacts.types, then the contacts::types translation, then the capitalized value. Publish contacts-translations to translate the built-in labels.

Enum helpers

ContactType also uses the Helpers trait from enums-for-laravel for select lists and validation. Its own config- and translation-aware label() takes precedence over the trait’s plain one:

ContactType::values();          // Collection: 'email', 'phone', 'address', 'url', 'social', 'custom'
ContactType::options();         // EnumOption DTOs {value, label, name} for selects
ContactType::validationRule();  // 'in:email,phone,address,url,social,custom'
$type->isIn([ContactType::Email, ContactType::Phone]);

validationRule() lists the six built-in values only. To accept registered custom kinds too, use ContactRules::kinds() — see Validation.

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.