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. |
sharingRule |
callcoreio.SharingRule |
The sharing context — either WithSharing or WithoutSharing. Propagated automatically when you use addFullScopeOf. |
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 instance. |
addFullScopeOf(Id linkedRecordId) |
Resolves the full communication scope for a linked record and merges it into this context. Null-safe. Sharing propagation, error forwarding, and circular-delegation protection are handled automatically. Use this instead of calling build() directly. |
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. Calling context.addFullScopeOf(linkedId) resolves the full communication scope for that record and merges it into the current context automatically. Sharing propagation, error forwarding, and circular-delegation protection are all handled by the package.
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);
context.addFullScopeOf(c.ContactId);
}
}
addFullScopeOf is null-safe — calling it with a null ID is a no-op. The method is chainable and returns this.
If the Contact's scope logic is later changed (via its own registered strategy), your implementation picks up that change automatically.
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.
- To include the full communication scope of a related record, call
context.addFullScopeOf(linkedId). Sharing propagation and circular-delegation protection are handled automatically — do not callbuild()directly.