Custom kinds
Any stored kind outside the six built-ins — for example a whatsapp kind registered in config — types as Custom and takes its label, icon and rules from contacts.types.<kind>:
// config/contacts.php
'types' => [
'whatsapp' => [
'label' => 'WhatsApp',
'icon' => 'chat-bubble',
'rules' => ['required', 'string', 'regex:/^\+?[1-9]\d{6,14}$/'],
],
],use RoundlyConsulting\Contacts\DataTransferObjects\ContactData;
use RoundlyConsulting\Contacts\Models\Contact;
$contact = $user->addContact(ContactData::fromArray([
'type' => 'whatsapp',
'value' => '+421900123456',
'name' => 'Support',
]));
$contact->kind; // 'whatsapp' — the raw kind, as stored
$contact->type; // ContactType::Custom
$contact->kindLabel(); // 'WhatsApp'
$contact->kindIcon(); // 'chat-bubble'
Contact::query()->ofType('whatsapp')->get(); // this kind onlyThe raw kind is kept alongside the type, so the registered label, icon and validation rules all resolve — the regex above rejects a bad value on addContact(). $contact->kind is what the registry is keyed by; $contact->type stays a ContactType for typing and is Custom for any kind outside the six.
Kind versus label
kindLabel() is the kind’s display name, distinct from $contact->label — your free-text label for one particular contact (for example Work). An unregistered kind is preserved but falls back to Custom’s label (Other) and icon (identification).
Independent kinds
Registered kinds are independent: each keeps its own primary contact and its own position sequence, and ofType('whatsapp') scopes to that kind alone — a new whatsapp primary never demotes a telegram one.
Adding and validating custom kinds
Every entry point keeps the raw kind: the fluent builder’s type('whatsapp'), ContactData::fromArray() with the kind as type, or the constructor’s kind argument. Pass the kind to ValidContactValue as well, or the registered rules never run:
use RoundlyConsulting\Contacts\DataTransferObjects\ContactData;
use RoundlyConsulting\Contacts\Enums\ContactType;
use RoundlyConsulting\Contacts\Facades\Contacts;
use RoundlyConsulting\Contacts\Rules\ValidContactValue;
use RoundlyConsulting\Contacts\Support\ContactRules;
// The fluent builder keeps the raw kind
Contacts::for($user)->type('whatsapp')->value('+421900123456')->add();
// The constructor form — pin the raw kind next to the Custom type
$user->addContact(new ContactData(ContactType::Custom, '+421900123456', kind: 'whatsapp'));
// Validate a form field against the registered kind's rules
$request->validate([
'whatsapp' => ['required', new ValidContactValue(ContactType::Custom, 'whatsapp')],
]);
// ...or take the ready rule array for the kind
$request->validate([
'whatsapp' => ContactRules::forValue(ContactType::Custom, 'whatsapp'),
]);Overriding built-in kinds
The same registry overrides the six built-ins — set a label, icon or rules for email, phone, address, url, social or custom:
// config/contacts.php — override a built-in kind's label, icon or rules
'types' => [
'url' => ['label' => 'Homepage', 'icon' => 'link'],
],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.