GatherPhoneNumbersFromRecords
What It Does
After BuildCommunicationScopeForRecord determines which records are in scope, the package needs to extract the phone numbers from those records. It then queries PhoneCall__c records whose external phone numbers match, which is how calls appear in the timeline.
By default:
- Contact —
Phone,MobilePhone,HomePhone,OtherPhone. - Account —
Phone. - Any other SObject — no phone numbers extracted (calls will not appear).
Implement GatherPhoneNumbersFromRecords.IStrategy to override extraction for a specific object type — for example, to read from a custom phone field, add numbers from a related list, or support a custom object entirely.
Interface
global interface IStrategy {
void gather(Context context);
}
Context
Input
| Field | Type | Description |
|---|---|---|
recordRefs |
callcoreio.RecordRefSet |
The set of records to extract phone numbers from. All records are the same SObject type. |
Access the IDs to query via context.recordRefs.toIdSet().
Write Methods
Call these from your gather implementation to record phone numbers:
| Method | Description |
|---|---|
add(callcoreio.RecordRef recordRef, String displayName, String phoneNumber) |
Adds a single phone number for a record. |
add(callcoreio.RecordRef recordRef, String displayName, Set<String> phoneNumbers) |
Adds multiple phone numbers for a record. |
add(Id recordId, String displayName, Set<String> phoneNumbers) |
Convenience overload accepting a raw Id. |
Phone number normalisation is applied automatically inside add(). You do not need to normalise numbers before passing them — pass them as they appear on the record. Null and blank values in the set are silently ignored.
Discriminator
The discriminator is RecordType:<SObjectApiName> where <SObjectApiName> is the API name of the object the strategy handles (e.g., RecordType:Contact, RecordType:MyObject__c).
Use default to provide a fallback for all object types without a more specific record. Note that the packaged default returns no phone numbers — if you want numbers extracted from an object not supported by default, you must register a record for it.
Default Behaviour
| Object | Fields gathered |
|---|---|
Contact |
Phone, MobilePhone, HomePhone, OtherPhone |
Account |
Phone |
| Anything else | None |
Example: Custom Object with Multiple Phone Fields
A custom object Supplier__c has fields MainPhone__c, EmergencyPhone__c, and Mobile__c.
public class GatherPhoneNumbersFromSuppliers
implements callcoreio.GatherPhoneNumbersFromRecords.IStrategy {
public void gather(callcoreio.GatherPhoneNumbersFromRecords.Context context) {
List<Supplier__c> suppliers = [
SELECT Id, Name, MainPhone__c, EmergencyPhone__c, Mobile__c
FROM Supplier__c
WHERE Id IN :context.recordRefs.toIdSet()
];
for (Supplier__c s : suppliers) {
context.add(
s.Id,
s.Name,
new Set<String>{ s.MainPhone__c, s.EmergencyPhone__c, s.Mobile__c }
);
}
}
}
Register with:
- Strategy Type:
GatherPhoneNumbersFromRecords - Discriminator:
RecordType:Supplier__c - Apex Class Name:
GatherPhoneNumbersFromSuppliers
Example: Overriding Contact to Add a Custom Field
To extend the built-in Contact extraction with an additional custom field DirectLine__c:
public class GatherPhoneNumbersFromContactsExtended
implements callcoreio.GatherPhoneNumbersFromRecords.IStrategy {
public void gather(callcoreio.GatherPhoneNumbersFromRecords.Context context) {
List<Contact> contacts = [
SELECT Id, FirstName, LastName, Phone, MobilePhone,
HomePhone, OtherPhone, DirectLine__c
FROM Contact
WHERE Id IN :context.recordRefs.toIdSet()
];
for (Contact c : contacts) {
context.add(
c.Id,
buildName(c),
new Set<String>{
c.Phone, c.MobilePhone, c.HomePhone,
c.OtherPhone, c.DirectLine__c
}
);
}
}
private String buildName(Contact c) {
List<String> parts = new List<String>();
if (!String.isBlank(c.FirstName)) parts.add(c.FirstName.trim());
if (!String.isBlank(c.LastName)) parts.add(c.LastName.trim());
return String.join(parts, ' ');
}
}
Register with:
- Strategy Type:
GatherPhoneNumbersFromRecords - Discriminator:
RecordType:Contact - Apex Class Name:
GatherPhoneNumbersFromContactsExtended
Notes
- The strategy is called once per SObject type in the scope. If both Contacts and Accounts are in scope, the Contact strategy and the Account strategy are each called separately with their respective
RecordRefSet. - Query
WHERE Id IN :context.recordRefs.toIdSet()— never query in a loop. The framework may pass multiple records at once. - The
displayNameparameter is used in the call record display. It is typically the record's name field. Pass an empty string if no name is available. - Phone numbers must already exist in Salesforce field values. The strategy cannot call external APIs.