NOTE: This guide covers the released FormulaShare versions up to v1.13. The updated help guide has been written for FormulaShare version 2.0 and higher, which would apply for any upgrades or installations from the AppExchange since 16 November 2020, as well as most sandboxes.
If you're not sure which version you're on, you can check this by looking for FormulaShare in the Installed Packages menu item in Setup - if version number starts with a 2 then your org has been upgraded.
In this guide, we’ll walk through the steps to install the FormulaShare package in a Salesforce org, create a FormulaShare rule and check that it’s working as expected.
Package installation
The simplest way to manage installation and upgrades is to install the managed package to a sandbox or production org from the AppExchange listing: https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000FR5TCUA1
The source code and all metadata configuration for FormulaShare is available on Github. Deploying to an org from files on Github is also possible, though out of scope of this guide.
Post installation setup
The first step to get going after installation is to schedule the FormulaShare batch job. This is the process used by the app to calculate and apply sharing.
To do this, navigate to the Salesforce Setup menu, type “Apex Classes” and click on the menu item. Click the “Schedule Apex button shown below:
Select the class “FormulaShareProcessSchedulable” to be scheduled.
Job Name can be anything - this distinguishes the processing job in the setup menu.
Apex Class should be set to “FormulaShareProcessSchedulable”.
Other parameters can be set to your preferred values. We’d recommend having the job run every day by setting Frequency to “Weekly” and ticking all of the days of the week.
Now we’re ready to configure some sharing logic!
Defining a sharing requirement
Sharing is all about who sees what. Describing sharing can feel abstract without a real world example, so the descriptions and screenshots in this guide all relate to the scenario below.
Let’s say we’re working for an international NGO, who fundraise donations for projects across Sub-Saharan Africa.
We hold records of donations in a custom object called... “Donation”. Donations are made for specific programmes running in one of the countries our NGO works in, and should be visible to the in-country finance staff working on those programmes:
The trouble is, our organisation is pretty big, and works in over 60 countries. Even if we could identify the country for the Donation object in a field, we wouldn’t be able to use criteria-based sharing to share to each of the country roles without bumping up against the Salesforce limit.
So, we’ll instead set up some FormulaShare sharing for the Donation object which makes use of its relationships with other objects.
1: A field on the object to be shared
We know what we want to share, right? Great!
FormulaShare can share any standard or custom object which supports sharing. That is to say, objects which aren’t on the detail side of a master-detail relationship, and have their org-wide default sharing setting set as either Private or Public Read Only.
For FormulaShare to know who should get access, we need a field on the object to be shared which has this information. This field can hold either the name or record id of the entity needing access. Supported entity types are:
In the screenshot below, we’re setting up a field on Donation which holds the name of the Finance Manager Role (a text field on the country records):
We can see the field populating below:
Note: If sharing to a role or public group, the exact Role Name or Group Name with should be populated in this field. This is shown against the specific role or public group in the setup menu.
It’s also possible to use the record id of a role or group here and configure the rule to use this instead.
In the case of sharing to a particular user, this must be done by populating record id (name is not supported).
2: Apex sharing reason for custom objects
The Apex Sharing Reason feature exists to help to manage different kinds of sharing on the same custom object. This is Salesforce’s way of applying a label to each sharing record so that it’s clear where this sharing came from.
If the object you want to share is a custom object, it’s recommended to set up a different sharing reason for each FormulaShare rule we need:
Initial setup of the sharing reason can only currently be done in Classic, so switch to this if necessary (click your picture in the top right and “Switch to Salesforce Classic”). Next open the setup page for the object to be shared (Setup -> Create -> Objects and click the object name). Scroll to “Apex Sharing Reasons”, click New, and set a reason label and name:
Copy the text of the name. This will be used in the next step.
NOTE: This step isn’t needed for standard objects, as Salesforce does not allow custom sharing reasons. See the end of the guide for more information on differences between FormulaShare used on custom and standard objects.
3: A FormulaShare Rule
Now that our records indicate who they need to be shared with, we can specify a rule to apply this sharing.
Click Setup and open “Custom Metadata Types”. Open “FormulaShare Rule”, and click the “Manage FormulaShare Rules” button at the top. From here click “New” to start defining the rule.
- Name and Label: Add something to distinguish this rule from others
- Shared Object: The API name (including "__c") of the object with records to be shared. Object must be set to Private (for Read or Edit access levels) or Public Read Only (for Edit access level), and must support sharing - child objects in a master-detail relationship and some standard objects do not support independent sharing rules
- Shared To Field: The API name (including "__c") of the field on the object above which identifies who to share records with. The field can return either the Salesforce 15 or 18 character Id of the entity to be shared to, or the role or group name (developer name) when the rule provides this sharing
- Shared to Field Type: Either "Id" or "Name", depending on return type of the Shared To Field
- Share With: The type of entity this rule should share with. Options are "Users", "Roles", "Roles and Internal Subordinates", "Roles, Internal and Portal Subordinates" (includes both community and portal users) and "Public Groups"
- Access Level: Set to Read or Edit
- Sharing Reason: For custom objects, paste the name of the Apex Sharing Reason copied in the last step and add “__c”. For standard objects, leave this blank.
Here’s an example of the rule to share our donation object with the role and subordinates of the in country finance manager role:
4: Real time processing
FormulaShare is designed to be implemented without any coding needed - in this case rules will recalculate each time the scheduled batch job runs (daily, if the job is set up in this way).
For more instant results, a very simple bit of custom development can ensure FormulaShare applies or revokes sharing every time a shared object is created or updated. This step is optional - without this sharing will still be assessed and applied every time the scheduled job runs, which is fine if users don't need access right away.
To get real time assessment, the following code should be called from the shared object’s trigger (after insert and update):
sdfs.FormulaShareHelper helper = new sdfs.FormulaShareHelper();
insert helper.getSharesToInsert();
delete helper.getSharesToDelete();
In our example, the apex trigger below will add or remove FormulaShare sharing where necessary for the Donation object each time donations are created or updated in a way which needs a sharing change:
trigger DonationTrigger on Donation__c (after insert, after update) {
sdfs.FormulaShareHelper helper = new sdfs.FormulaShareHelper();
insert helper.getSharesToInsert();
delete helper.getSharesToDelete();
}
If implementing a trigger in this way, a corresponding test class like the one below is needed to give full code coverage:
@IsTest public class DonationTriggerTest {
@IsTest
public static void testInsert() {
Donation__c d = new Donation__c();
insert d;
System.assert(d.Id != null);
}
}
Note this is an illustration of a simple implementation where no other trigger code exists, no trigger helper / handler is used, and the shared object does not have any mandatory fields.
If trigger helper / handler classes or a trigger framework is used in your org, code to call FormulaShare methods can be added to an appropriate place in the methods managing record inserts or updates.
Note that FormulaShare functionality will assess whether any changes to sharing are required, and only update records when necessary. This means it’s not necessary to check these conditions before calling FormulaShare.
Check that sharing is working
Sharing will be updated when triggers run (see step above), or each time the batch jobs runs (for example daily - see “Post Installation Setup”).
There are a few ways to check that sharing is being applied as expected:
- Log in as a user who should now have access, and check they can view or edit the record
- Query the object’s share table using SOQL (for example select Id, UserOrGroupId, RowCause from Donation__Share where ParentId = <id of record which should be shared>)
- Click the “Sharing” button from the record in Salesforce Classic
To check sharing on the record in the UI (number 3 above), switch to Salesforce Classic if necessary, navigate to the record and click “Sharing”:
Note that if you don’t see the sharing button, this could be due to one of the reasons below:
- Sharing button is not on the page layout
- Your user does not have full access to the record (this will be the case if you’re not the record owner or a system admin)
- The object’s organisation-wide default is public read/write. In this case sharing is not relevant for the object as all users can view and edit all records, so FormulaShare rules will be ignored
The list shown will include any sharing applied by FormulaShare, as well as other sharing relevant to this record:
Note that the “Reason” shown corresponds to the Apex Sharing Reason set up in step 2.
Additional things to be aware of...
Standard vs custom objects
For custom objects, Apex Sharing Reasons enable FormulaShare to distinguish sharing applied by the app, and other apex and manual sharing used on the object. When records change in a way that FormulaShare sharing is no longer needed, the FormulaShare sharing under this Apex Sharing Reason no longer meeting the criteria of the FormulaShare rule are deleted.
For standard objects, sharing reasons aren't available, so FormulaShare can’t be sure whether sharing on a record was applied by FormulaShare or manually. To tackle this situation, FormulaShare provides two options for managing sharing on standard objects.
Standard Objects Option 1 - Additive
By default, sharing for standard objects will be added by FormulaShare but not removed. This means if there’s a data change which means that different sharing should apply, the new sharing will be created, but the old sharing not removed. For example, say FormulaShare shares Contacts to a public group which is set on the Country record they’re linked to. If a contact was linked to Malawi, it would be shared with the Malawi public group. If the contact is later changed to be associated with Zimbabwe instead, it would be shared with the Malawi public group, but also continue to be shared with the Zimbabwe public group.
Standard Objects Option 2 - Fully Managed
If requirements are such that sharing must be removed on a standard object, FormulaShare can be configured to remove ALL sharing on an object which doesn’t meet the criteria of the current active rules. This will remove any FormulaShare sharing which is no longer applicable, but will ALSO remove any other apex sharing and manual sharing applied in the org. This option should only be used if we’re sure manual sharing and apex sharing are not used on the object.
To set FormulaShare up to process an object in this way, create a record in the “FormulaShare Std Object to Remove Shares” custom metadata type.
FormulaShare Logs
Log records are created each time a batch job runs. These indicate the processing time of the batch job and the objects which have had sharing recalculated. To access logs, check the object “FormulaShare Logs”, which is available to all admins in the org, as well as any users who are assigned the permission set “FormulaShare Admin User"