BuildCommunicationScopeForRecord
What It Does
When a user opens the CallCore timeline on a record page, the package needs to know which CRM records are "in scope" — that is, which records should be checked for matching phone numbers when retrieving call history.
By default:
- Contact page — the Contact itself plus its parent Account.
- Account page — the Account plus all its Contacts.
- Opportunity page — the Opportunity plus its Account (delegating to the Account scope logic).
- Any other record — the anchor record only.
Implement BuildCommunicationScopeForRecord.IStrategy to replace this logic for a specific object type or to add support for a custom object.
Interface
global interface IStrategy {
void build(Context context);
}
Context
Input
| Field | Type | Description |
|---|---|---|
anchorRef |
callcoreio.RecordRef |
The record the timeline is being viewed from. Provides recordId and sObjectType. |
Write Methods
Call these from your build implementation to add records to the scope:
| Method | Description |
|---|---|
addToScope(Id id) |
Adds a single record ID to scope. Null-safe. |
addToScope(Iterable<Id> ids) |
Adds multiple record IDs. Null-safe. |
addToScope(callcoreio.RecordRef recordRef) |
Adds the ID from a RecordRef. Null-safe. |
addToScope(Context otherContext) |
Merges the scope from another Context (for delegation). |
addError(callcoreio.Error error) |
Records a non-fatal error (e.g., ScopeTooLargeError). |
Read Properties
| Property | Type | Description |
|---|---|---|
hasErrors |
Boolean |
True if any errors were added via addError. |
Discriminator
The discriminator is RecordType:<SObjectApiName> where <SObjectApiName> is the API name of the object the strategy applies to (e.g., RecordType:Contact, RecordType:Opportunity__c).
Use default to provide a fallback for all object types that do not have a more specific record.
Default Behaviour
| Object | Default scope |
|---|---|
Contact |
Contact + parent Account |
Account |
Account + child Contacts |
Opportunity |
Opportunity + Account (Account's default scope applies) |
| Anything else | The anchor record only |
Errors
callcoreio.ScopeTooLargeError is a built-in error type for when a query would return too many records to build a usable scope. Add it via context.addError(error) — the framework will surface it to the UI without halting execution.
global class ScopeTooLargeError extends callcoreio.Error {
global List<callcoreio.RecordRef> contextRecords;
global String relationSObjectApiName;
global String relationshipName;
global Integer relationCount;
global Integer maxAllowedRelationCount;
}
Example: Custom Object with a Lookup to Account
A custom object Project__c has a Account__c lookup. When the timeline is viewed from a Project record, include the Project itself plus its linked Account.
public class BuildProjectCommsScope
implements callcoreio.BuildCommunicationScopeForRecord.IStrategy {
public void build(callcoreio.BuildCommunicationScopeForRecord.Context context) {
Project__c project = [
SELECT Id, Account__c
FROM Project__c
WHERE Id = :context.anchorRef.recordId
LIMIT 1
];
context
.addToScope(project.Id)
.addToScope(project.Account__c);
}
}
Register with:
- Strategy Type:
BuildCommunicationScopeForRecord - Discriminator:
RecordType:Project__c - Apex Class Name:
BuildProjectCommsScope
Example: Delegating to Another Record's Scope
Use this pattern when your custom object has a lookup to a Contact and you want to inherit Contact's default scope behaviour — the Contact itself plus its parent Account — without reimplementing that logic. Rather than querying the Account directly, you call BuildCommunicationScopeForRecord.build with the Contact's ID and merge the result. If the Contact's scope logic is later changed (via its own registered strategy), your implementation picks up that change automatically.
public class BuildCaseCommsScope
implements callcoreio.BuildCommunicationScopeForRecord.IStrategy {
public void build(callcoreio.BuildCommunicationScopeForRecord.Context context) {
Case c = [
SELECT Id, ContactId
FROM Case
WHERE Id = :context.anchorRef.recordId
LIMIT 1
];
context.addToScope(c.Id);
if (c.ContactId != null) {
callcoreio.BuildCommunicationScopeForRecord.Context contactCtx =
callcoreio.BuildCommunicationScopeForRecord.build(c.ContactId);
context.addToScope(contactCtx);
}
}
}
Notes
- The anchor record is not automatically added to scope. If you want it included, call
context.addToScope(context.anchorRef)explicitly. - Records from different SObject types can be added to the same scope. The package groups them by type internally before passing to
GatherPhoneNumbersFromRecords. - Scope building happens once per timeline request. Avoid SOQL inside loops — the anchor is a single record, but related queries should be written in bulk-safe fashion if you anticipate the strategy being invoked for multiple records in future.