+ Start a Discussion
DanielJimenezDanielJimenez 

Some useful Chatter Utils I wrote.

New to VisualForce/Apex/Salesforce in general. I've created some methods I found very useful and thought I'd share. Just fair warning that these could most definitely be improved upon. I welcome any recommendations and feel free to use this code, I hope you find it useful.

 

 

 

public class ChatterUtils {
    @future
    static public void addFollower(Id userId, Id objectToFollowId) {
        EntitySubscription e = new EntitySubscription();
        e.subscriberId = userId;
        e.parentId = objectToFollowId;
        Database.insert(e,false);
    }
    
    @future
    static public void addFollowers(Set<Id> userIds, Id objectToFollowId) {
        EntitySubscription[] es = new List<EntitySubscription>();
        for (Id userId : userIds) {
            EntitySubscription e = new EntitySubscription();
            e.subscriberId = userId;
            e.parentId = objectToFollowId;
            es.add(e);
        }
        Database.insert(es,false);
    }
    
    @future
    static public void copyFollowers(Id objectToCopyFrom, Id objectToFollowId) {
        User[] users = [select id from user where id in 
                (select subscriberId from EntitySubscription where parentId = :objectToCopyFrom)];
        EntitySubscription[] es = new List<EntitySubscription>();
        for (User user : users) {
            EntitySubscription e = new EntitySubscription();
            e.subscriberId = user.Id;
            e.parentId = objectToFollowId;
            es.add(e);
        }
        Database.insert(es,false);
    }
    
    @future
    /**
    	This crazy method takes two side by side arrays, both with sObject Ids. The arrays must both be the same size.
    	Followers are copied from/to in the exact same order they are both in, in the array. Very useful in triggers on joining objects.
    **/
    static public void copyFollowers(Id[] objectsToCopyFrom, Id[] objectsToFollow) {
        System.assertEquals(objectsToCopyFrom.size(),objectsToFollow.size());
        System.debug(Logginglevel.INFO,'Objects same size?: ' + (objectsToCopyFrom.size() == objectsToFollow.size()) + '. Size is ' + objectsToCopyFrom.size());
        Integer size = objectsToFollow.size();
		EntitySubscription[] es = new List<EntitySubscription>();        
        
		//Creating the Map that lets us get all the followers by their parent Id.
        EntitySubscription[] allEntitySubs = [select subscriberId,parentId from EntitySubscription where parentId in :objectsToCopyFrom];
      	
      	if (allEntitySubs.size() > 0) {
      		Map<Id,Id[]> followerMap = new Map<Id,Id[]>();
	        for (EntitySubscription es1 : allEntitySubs) {
	        	if (followerMap.containsKey(es1.parentId)) {
	        		followerMap.get(es1.parentId).add(es1.subscriberId);
	        	} else {
	        		Id[] esList = new List<Id>();
	        		esList.add(es1.subscriberId);
	        		followerMap.put(es1.parentId,esList);
	        	}
	        }
	        System.debug(LoggingLevel.info,'Map size: ' + followerMap.size());
	        
	        //This creates the EntitySubscription.
	        for (Integer i = 0; i < size; i++) { //Using an old school loop so we can go through both arrays.
	        	System.debug(Logginglevel.info,'Copying all followers from: ' + objectsToCopyFrom[i]);
	        	if (followerMap.get(objectsToCopyFrom[i]) != null) {
	        		for (Id followerId : followerMap.get(objectsToCopyFrom[i])) {
		                EntitySubscription e = new EntitySubscription();
		                e.subscriberId = followerId;
		                e.parentId = objectsToFollow[i];
		                System.debug(Logginglevel.INFO,e);
		                es.add(e);
	            	}	
	        	}
	        }
	        System.debug(Logginglevel.INFO,'Adding ' + es.size() + ' followers.');
	        Database.insert(es,false);
      	}
    }
    
    @future
    static public void addRelatedPost(String title, String body, Id parentId, Id relatedObjectId) {
        FeedPost issuePost = new FeedPost();
        issuePost.Type = 'LinkPost';
        issuePost.ParentId = parentId;
        issuePost.Title = title;
        issuePost.Body = body;
        issuePost.LinkUrl= '/' + relatedObjectId;
        insert issuePost;
    }
    
    static testMethod void test(){
 		Map<Id,Account> accounts = new Map<Id,Account>([select id from account limit 10]);
 		Account account = [select id,ownerid from Account limit 1];
 		Map<Id,User> users = new Map<Id,User>([select id from user]);
 		User user = [select id from User limit 1];
 		
 		ChatterUtils.copyFollowers(account.id,account.ownerId);
 		ChatterUtils.addFollower(account.id,account.ownerId);
    }
    
    static testMethod void testNoFollowers() {
    	Account account = new Account(Name='Test');
    	insert account;
    	Case aCase = new Case();
    	insert aCase;
    	
    	Id[] list1 = new List<Id>();
    	list1.add(account.id);
    	Id[] list2 = new List<Id>();
    	list2.add(aCase.id);
    	ChatterUtils.copyFollowers(list1,list2);
    }
}

 

 

I really use the copyFollowers() method a lot. I use it for triggers on junction objects. For example, we have an object called CaseIssue for a many-to-many relationship between Cases and Issues.

 

 

trigger CaseIssueChatter on CaseIssue__c (after insert) {
	Set<Id> caseIds = new Set<Id>();
	Set<Id> issueIds = new Set<Id>();
     for (CaseIssue__c ci : Trigger.new) {
     	caseIds.add(ci.Case__c);
     	issueIds.add(ci.Issue__c);
     }
     ChatterUtils.copyFollowers(caseIds,issueIds);
}

 

 

We also like our Cases to copy the followers of the Account, so they are able to stay in the loop with their customer's cases. 

 

 

trigger CaseChatter on Case (after insert, after update) {
    Id[] caseIds = new List<Id>();
    Id[] accountIds= new List<Id>();
    for (Case newCase : Trigger.new) {
        caseIds.add(newCase.id);
        accountIds.add(newCase.accountId);
    }
    ChatterUtils.copyFollowers(accountIds, caseIds);
}

 

I had a hard time making these usable in bulk so I figure if our org is the only one using it, it's sort of a waste. Most of my frustration was due to using @future I think, but it seemed to be appropriate.

 

Also I don't have all my unit tests included here, as some of them are pretty specific to our environment.

 

Daniel

 

cloudcodercloudcoder

Thanks for the contribution! Some of the utils are similar to the Chatter Commons project on codeshare. The ones that are not, you should certainly think about adding to the project so all can share the love :)

 

Quinton

DanielJimenezDanielJimenez
I was thinking the same thing! I'm not sure the code is up to par with Chatter Commons, but I'd be happy to hear the authors opinion.