Chatter triggers in Spring 11

In spite of my worse fears, I did manage to make it for a 6am PST webinar (repeated @ 10am) that Dave Carroll and I presented recently on the new platform features coming in the Spring 11 release. Other than the early start time, the hardest thing for me in preparing for the webinar was deciding which features to highlight in the limited time that we had. The Spring 11 release is chock-a-block with great new platform features including Chatter triggers, a new Apex Testing framework, Field Sets (that lets Admins configure Visualforce pages), Dynamic VF, Javascript Remoting, GA of the REST API and many more. Dave and I covered most of those topics during our webinar and you can watch the recording and check out the release website to get up to speed.

I wanted to post the code for the demos that we did during the webinar to help developers get familiar with the new features (and to prove that it wasn't smoke and mirrors!). I'll start with the Chatter trigger sample and will be blogging about other samples in the next couple of days. You can jump to this mark in the recording if you're only interested in the Chatter trigger demo and would rather not listen to the brilliant repartee between Dave and myself (tongue firmly in cheek).

To recap, Spring 11 introduces the ability to create Apex triggers on the FeedItem and FeedComment objects. Developers can now trigger real time business actions every time that someone posts to a User/Entity Feed or when someone comments on an existing post. The demo that I gave during the webinar addressed the following use case – "An AE can close an Opportunity (updating the Close Date and Stage and creating a reminder follow-up Task) by simply typing '!close' into the entity feed for the record".  You can imagine why AEs would love such functionality if they were out in the field and wanted a quick way to close an Opportunity via their iXXX/Android/BB.

Here's the trigger code:

trigger CloseOpportunity on FeedItem (after insert) {
Set<Id> oppIds = new Set<Id>();
List<Task> tasks = new List<Task>();
List<Opportunity> opps2Update = new List<Opportunity>();
Map<Id, Id> oppId2PostCreator = new Map<Id, Id>();
//Get the key prefix for the Opportunity object via a describe call.
String oppKeyPrefix = Opportunity.sObjectType.getDescribe().getKeyPrefix();
for (FeedItem f : trigger.new)
{
String parentId = f.parentId;
//We compare the start of the 'parentID' field to the Opportunity key prefix to
//restrict the trigger to act on posts made to the Opportunity object.
if (parentId.startsWith(oppKeyPrefix) &&
f.type == 'TextPost' &&
f.Body.startsWith('!close'))
{
oppIds.add(f.parentId);
oppId2PostCreator.put(f.parentId, f.CreatedById);
}
}
List<Opportunity> opps = [select id, account.name, ownerId, stageName, closeDate
from Opportunity
where id in :oppIds];
for (Opportunity o : opps)
{
//We compare the creator of the Chatter post to the Opportunity Owner to ensure
//that only authorized users can close the Opportunity using the special Chatter 'hot-key'
if (oppId2PostCreator.get(o.Id) == o.ownerId)
{
o.StageName = 'Closed Won';
o.CloseDate = System.today();
Task t = new Task ( OwnerId = o.OwnerId,
WhatId = o.Id,
Priority = 'High',
Description = 'Check-in with '+account.name,
Subject = 'Follow-up',
ActivityDate = System.today().addDays(7));
tasks.add(t);
opps2Update.add(o);
}
}
update opps2Update;
insert tasks;
}

Lets walk through the code. First, notice that you write the trigger on a new 'generic' FeedItem object. You can't write triggers on the UserFeed or AccountFeed/OpportunityFeed etc. objects. That means that the trigger can fire as a result of several different actions – someone posting to a user's feed or someone posting to the entity feed of any object for which Chatter is enabled (Account, Opportunity, custom object etc.). Therefore, if your trigger code is only applicable to a specific user or entity feed (in this case, Opportunity), you need to filter for those posts in the trigger code. The best way to do so is to compare the prefix of the polymorphic 'parentId' field on the FeedItem object (which would map to the user/record for which the Chatter post was added) with the key prefix of the entity that you're interested in. That's exactly what lines 8 & 15 do.

Another point of note is the events that can trigger (no pun intended) a FeedItem or FeedComment Trigger. Since Chatter posts/comments can only be inserted or deleted (they cannot be updated or undeleted by a user), the triggers only support the 'insert' and 'delete' events. 

A final note. FeedItems of type 'UserStatus' and 'TrackedChange' don't invoke the triggers. In other words, if a user updates his/her own status in Chatter or if a tracked field changes value, those events won't fire any triggers. Instead, you can write a trigger on the respective SObject if you want to act on a change to a field value and you can write a trigger on the User object for taking some action based on a user updating his/her Chatter status.

The rest of the trigger code is relatively straightforward and I won't delve into it. Happy coding and let me know if you have any questions about the trigger code.

Published
January 31, 2011
Topics:

Leave your comments...

Chatter triggers in Spring 11