4

If I was trying to compare a lot of strings, my code is quite easily read (I feel) but I know there is a lot of duplication. Especially when the field values are the same, is there a tidier way of writing this. This is expected to be ran in a beforeInsert context and I have 13 spam cases to capture and maybe another 10 more customised cases.

//Spam Cases
        for (case cs : newCase){
            String comparetext = cs.subject.tolowerCase();
            Boolean result = comparetext.contains('whisky inactive users deleted');
            if (result){
                cs.type = 'Spam';
                cs.reason = 'Spam';
                cs.status = 'Closed';
                cases2Update.add( cs );     
            }

            comparetext = cs.subject.tolowerCase();
            result = comparetext.contains('out of office');
            if (result){
                cs.type = 'Spam';
                cs.reason = 'Spam';
                cs.status = 'Closed';
                cases2Update.add( cs );     
            }

            comparetext = cs.subject.tolowerCase();
            result = comparetext.contains('Automatic Reply');
            if (result){
                cs.type = 'Spam';
                cs.reason = 'Spam';
                cs.status = 'Closed';
                cases2Update.add( cs );     
            }

            comparetext = cs.subject.tolowerCase();
            result = comparetext.contains('Your order is due for delivery by Parcel');
            if (result){
                cs.type = 'Spam';
                cs.reason = 'Spam';
                cs.status = 'Closed';
                cases2Update.add( cs );     
            }


        }
update cases2Update;

Edit: I am currently taking apart 3 different approval processes and 2 workflow rules inserting it all into a method executed on the beforeInsert context of cases. This will help me assign ownership easier and set default values as below shows. (hopefully).

Edit: I ended up creating a custom object for holding the settings. I then created the following code which is much shorter and in my first 5 tests, worked fine, Contains_Text__c is the custom field that contains the text to compare against. The rest is just fluff...

 public static void updateNewCases(List<case> newCase){      

    //Is this method enabled by the admin settings.
    List<Admin_Settings__c>classSettingsList = [SELECT Id, setting__c, Status__c, Sobject__c FROM Admin_Settings__c WHERE setting__c = 'updateNewCases' AND sobject__c = 'Case' LIMIT 1];
        for (Admin_Settings__c settings :  classSettingsList){
        system.debug('status is' + settings.Status__c);
            if (settings.Status__c != 'Live'){
                system.debug('BREAKING OUT OF updateNewCases');
                return;
            }
    }

    List<Admin_Settings__c> AdminSettingsList = [SELECT Id, Contains_Text__c,Case_Status__c, Case_Reason__c, Case_Type__c, Queue_Id__c FROM Admin_Settings__c WHERE Status__c = 'Live'];
        List<Case> cases2Update = new List<Case>();

        for (Case cs : newCase){
            String compareText = cs.subject.toLowerCase();
            for (Admin_Settings__c settings : AdminSettingsList) {
                Boolean StringCheck = compareText.contains(settings.Contains_Text__c);
                if (StringCheck){    
                    cs.type = settings.Case_Type__c;
                    cs.reason = settings.Case_Reason__c;
                    cs.status = settings.Case_Status__c;
                    cs.OwnerId = settings.Queue_id__c;
                    return;
                }
            }
        }
    }
  • 1
    This would probably be a better fit over at Code Review – Derek F Jan 20 at 15:39
  • 4
    FYI, if you changed it to "before insert" you could avoid the recursive update. – sfdcfox Jan 20 at 16:17
  • I always listen to the fox - your first blog post (the aggregate query update pattern) is still great :D – sfdc_beginner1 Jan 20 at 16:35
9

I would factor your spam strings out and store them in the database, as a Custom Object, List Custom Setting, or Custom Metadata Type (the choice would depend on who maintains them and whether you need to deploy them between environments).

Then, you'll have the freedom to alter your spam catcher without performing a code deployment.

Your code would reduce to something resembling this:

Set<String> spamStrings = new Set<String>();
for (Spam_Subject__c subj : [SELECT Subject__c FROM Spam_Subject__c]) {
    spamStrings.add(subj.Subject__c);
}

for (case cs : newCase){
    String compareText = cs.subject.toLowerCase();
    for (String badSubject : spamStrings) {
        if (compareText.contains(badSubject){
            cs.type = 'Spam';
            cs.reason = 'Spam';
            cs.status = 'Closed';
            cases2Update.add(cs);     
            break;
        }
     }
}
|improve this answer|||||
  • Fantastic Idea - on it already, custom object will allow users to add new values as well so that is some really nice functionality. I will actually include type/reason, status and owner fields on that object as it will allow me to substantially reduce code if I manage everything in that object. – sfdc_beginner1 Jan 20 at 15:49
  • 3
    We did this not using a custom object but instead using a custom metadata type and various instances of that type. This allows us to (managed) package standard values while also allowing customers to add their own (and to transfer from one org to another via change sets). We even ensured there was a field that could "disable" specific instances (so our query says "WHERE Disabled__c != TRUE" for example) allowing the customer to turn off our packaged cases even though they are unable to actually delete them. – Phil W Jan 20 at 15:52
  • Thanks I just need to tweak the code to pull in multiple field values from the custom object (I am sole admin of the org so thought this was simplest) but I appreciate all the advise. – sfdc_beginner1 Jan 20 at 16:26
  • I think I need help bulkifying this using a custom object, I am trying to pull 4 or 5 fields in from the object to then update the case fields as above but getting a lot of errors. I need to read into it more tomorrow. Thanks for the help. – sfdc_beginner1 Jan 20 at 17:09
  • 2
    @sfdc_beginner1 Here's my recommendation. Get the "simple" case working first: custom object just for holding subject lines. When you have that working, commit it to version control, then start on the more complex idea you have in mind. It's always easier to solve complex code-based implementations if you let yourself break it down into building blocks. And of course, feel free to open more questions when you get truly stuck! – David Reed Jan 20 at 19:26
5

You can use Regex for your requirement. For example:

List<String> spamString = new List<String>{
    'out of office', 
    'whisky inactive users deleted'
}; // And others
Pattern myPattern = Pattern.compile('.*(' + String.join(spamString, '|') + ').*');
for (case cs : newCase) {
    String comparetext = cs.subject.tolowerCase();
    Matcher myMatcher = myPattern.matcher(comparetext);
    if (myMatcher.matches()) {
        cs.type = 'Spam';
        cs.reason = 'Spam';
        cs.status = 'Closed';
        cases2Update.add(cs);
    }
}

Note the .* in the spam strings, that means that there can be any text before and after these strings. You can play around with Regex strings to achieve the desired results

|improve this answer|||||
  • 2
    +1, though slightly more compact could be .*(string1|string2|string3|string4).* – sfdcfox Jan 20 at 16:16
  • @sfdcfox thanks, you are right(just like always I assume? :) )! – Novarg Jan 21 at 9:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.