When you are diving into, the huge ocean of Salesforce development! Navigating through it’s many tools and features is, a task of high intimidation. Amongst these, Apex classes is, standing as the backbone, of custom functionalities in the Salesforce ecosystem. In this blog post will aim to illuminate a light on 10 Salesforce Apex Classes Every Developer Should Know.
Let’s dig deep, shall we?
The Power of Apex
Apex is a OOPS programming language provided by Salesforce. It’s a strongly typed, object-oriented language that allows developers to execute flow and transaction control statements on the Salesforce platform server, in conjunction with calls to the API. Understanding and utilizing the right Apex classes can not only streamline your development process but also open up a plethora of customization options that can be tailored to specific business needs.
1. The System Class: The Root of All Apex
At the heart of Apex’s extensive library lies the System class. This class provides a collection of static methods that perform operations related to limits, logging, debugging, and testing. A deep dive into the System class can offer insights into:
Debugging and Logging
System.debug(logLevel, message)
: This method is crucial for developers to understand the inner workings and data manipulations happening within their code at runtime.System.assert()
,System.assertEquals()
, andSystem.assertNotEquals()
: These methods are vital for implementing test classes, ensuring your code behaves as expected.
public class SampleTestClass { public static void testMethod() { // Example of System.debug String logLevel = 'INFO'; String message = 'Debugging information'; System.debug(logLevel, message); // Example of System.assert Integer num1 = 5; Integer num2 = 10; System.assert(num1 < num2, 'num1 should be less than num2'); // Example of System.assertEquals Integer expectedValue = 100; Integer actualValue = 100; System.assertEquals(expectedValue, actualValue, 'Values should be equal'); // Example of System.assertNotEquals String expectedString = 'Hello'; String actualString = 'World'; System.assertNotEquals(expectedString, actualString, 'Strings should not be equal'); } }
Understanding Limits
: Knowing governor limits is integral for efficient Apex development, you can useLimits
Limits
class to retrieve information about various governor limits. Below is a sample class demonstrating how you can useLimits
class to get information about different governor limits.
public class LimitInfo { public static void displayLimits() { Integer limitSoqlQueries = Limits.getLimitQueries(); Integer limitSoqlRows = Limits.getLimitQueryRows(); Integer limitSoslQueries = Limits.getLimitDmlStatements(); Integer limitSoslRows = Limits.getLimitDmlRows(); Integer limitEmailInvocations = Limits.getEmailInvocations(); Integer limitQueueableJobsBatchSize = Limits.getLimitQueueableJobs(); Integer limitAsyncCalls = Limits.getLimitAsyncCalls(); Integer limitCallouts = Limits.getCallouts(); System.debug('SOQL Queries Limit: ' + limitSoqlQueries); System.debug('SOQL Rows Limit: ' + limitSoqlRows); System.debug('SOSL Queries Limit: ' + limitSoslQueries); System.debug('SOSL Rows Limit: ' + limitSoslRows); System.debug('Email Invocations Limit: ' + limitEmailInvocations); System.debug('Queueable Jobs Batch Size Limit: ' + limitQueueableJobsBatchSize); System.debug('Async Calls Limit: ' + limitAsyncCalls); System.debug('Callouts Limit: ' + limitCallouts); } }
2. The Database Class: Handling DML Operations
Salesforce data manipulation language (DML) operations are at the core of data handling, and the Database class offers methods that provide more flexibility and control compared to traditional DML statements like insert
, update
, or delete
.
Key Methods and Their Use-Cases
Database.insert(records, allOrNone)
: This method allows you to insert records with a choice to either allow partial success (by settingallOrNone
to false) or require all records to be inserted successfully.Database.query(queryString)
: Dynamically querying records enables developers to construct more versatile and responsive applications.
public class DatabaseOperations { public static void insertRecords(List<Account> records, Boolean allOrNone) { // Insert records with the specified behavior Database.SaveResult[] results = Database.insert(records, allOrNone); // Iterate through the results to check success or failure for (Database.SaveResult result : results) { if (result.isSuccess()) { System.debug('Record with Id: ' + result.getId() + ' was inserted successfully.'); } else { for(Database.Error error : result.getErrors()) { System.debug('Error occurred while inserting record: ' + error.getMessage()); } } } } public static List<Account> queryAccounts(String queryString) { // Execute the query and return the result return Database.query(queryString); } }
3. The Trigger Class
Understanding the context of execution is pivotal in writing efficient triggers. Apex provides the Trigger
class, which houses context variables offering insights into the state of the data and operation being performed.
Utilizing Context Variables
Trigger.New
: A collection of new records in aninsert
orupdate
trigger.Trigger.OldMap
: A map of IDs to the old versions of the sObjects before the update or delete operation.
trigger AccountTrigger on Account (before insert, before update, before delete, after insert, after update, after delete, after undelete) { // This trigger will run before and after different types of operations on the Account object if (Trigger.isBefore) { if (Trigger.isInsert) { // Logic before inserting Account records for (Account acc : Trigger.new) { // Perform actions on the new records being inserted } } else if (Trigger.isUpdate) { // Logic before updating Account records for (Account oldAcc : Trigger.old) { // Perform actions on the old records before they are updated } for (Account newAcc : Trigger.new) { // Perform actions on the new records being updated } } else if (Trigger.isDelete) { // Logic before deleting Account records for (Account acc : Trigger.old) { // Perform actions on the records being deleted } } } else if (Trigger.isAfter) { if (Trigger.isInsert) { // Logic after inserting Account records for (Account acc : Trigger.new) { // Perform actions on the new records that have been inserted } } else if (Trigger.isUpdate) { // Logic after updating Account records for (Account oldAcc : Trigger.old) { // Perform actions on the old records after they have been updated } for (Account newAcc : Trigger.new) { // Perform actions on the new records after they have been updated } } else if (Trigger.isDelete) { // Logic after deleting Account records // Note: You cannot access Trigger.new in after delete context for (Account acc : Trigger.old) { // Perform actions on the records that have been deleted } } else if (Trigger.isUndelete) { // Logic after undeleting Account records for (Account acc : Trigger.new) { // Perform actions on the records that have been undeleted } } } }
trigger AccountTrigger on Account (before update) { // This trigger runs before updating Account records // Accessing old records map Map<Id, Account> oldMap = Trigger.oldMap; // Accessing new records map Map<Id, Account> newMap = Trigger.newMap; // Iterate through the old records map for (Id accountId : oldMap.keySet()) { Account oldAccount = oldMap.get(accountId); // Perform actions on the old version of the record } // Iterate through the new records map for (Id accountId : newMap.keySet()) { Account newAccount = newMap.get(accountId); // Perform actions on the new version of the record } }
These variables are indispensable for writing triggers that interact intelligently with data, ensuring that your business logic executes seamlessly across different scenarios.
4. The Test Class: Ensuring Code Quality
Apex testing is not just a best practice; it’s a requirement for deployment. The Test
class provides methods that facilitate the creation of test data and the execution of test scenarios, ensuring your application is both robust and reliable.
Methods to Know
Test.startTest()
andTest.stopTest()
: These methods delineate a test scenario, allowing you to test governor limit consumption separately from the setup phase of your test.Test.setMock()
: It allows for mocking external callouts, making it possible to test integrations without hitting actual endpoints.
Example
Let’s assume we have a simple Apex class AccountService
which makes a callout to an external HTTP service to retrieve account information:
public class AccountService { public static List<Account> fetchAccountsFromExternalService() { // Code to make HTTP callout and retrieve account information // For simplicity, let's assume the callout is made to an external service // and returns a list of accounts return new List<Account>(); } }
now, let’s write a test class for AccountService
. We’ll use Test.startTest()
and Test.stopTest()
to demarcate the portion of code where we’re testing the callout:
@isTest private class AccountServiceTest { // Mock class to simulate the HTTP callout response private class MockHttpResponseGenerator implements HttpCalloutMock { public HTTPResponse respond(HTTPRequest req) { // Create a mock HTTP response HTTPResponse res = new HTTPResponse(); res.setHeader('Content-Type', 'application/json'); res.setBody('{"Id": "001R000001OoAKI", "Name": "Test Account"}'); res.setStatusCode(200); return res; } } @isTest static void testFetchAccountsFromExternalService() { // Set up mock HTTP callout Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator()); Test.startTest(); // Call the method being tested List<Account> accounts = AccountService.fetchAccountsFromExternalService(); Test.stopTest(); // Assert the results System.assertEquals(1, accounts.size()); System.assertEquals('001R000001OoAKI', accounts[0].Id); System.assertEquals('Test Account', accounts[0].Name); } }
5. The Http Class: Making Callouts
Integrating Salesforce with external services requires making HTTP callouts. The Http
class along with HttpRequest
and HttpResponse
classes enable developers to seamlessly connect and interact with external APIs.
A Simple Callout Example
Constructing a HttpRequest
, setting its endpoint and method, and then using an Http
instance to send the request is a straightforward process that opens up endless integration possibilities.
// Import necessary classes import http.*; public class HttpCalloutExample { // Method to make HTTP callout public static void makeCallout() { // Instantiate a new HTTP request object HttpRequest req = new HttpRequest(); // Set the endpoint URL for the request req.setEndpoint('https://api.example.com/resource'); // Set the HTTP method (GET, POST, etc.) req.setMethod('GET'); // Instantiate a new HTTP object to send the request Http http = new Http(); try { // Send the HTTP request and store the response HttpResponse res = http.send(req); // Check if the request was successful (status code 200) if (res.getStatusCode() == 200) { // Process the response body String responseBody = res.getBody(); System.debug('Response: ' + responseBody); } else { // Handle the error response System.debug('Error: ' + res.getStatus() + ' - ' + res.getStatusText()); } } catch (Exception e) { // Handle any exceptions System.debug('Exception: ' + e.getMessage()); } } }
6. The Batchable Interface: Processing Large Data Sets
Salesforce provides the Database.Batchable<SObject>
interface for processing records in batches, allowing for operations that exceed governor limits for DML rows or SOQL queries.
Implementing Batch Class
Implementing a class that implements Database.Batchable<SObject>
involves defining three methods: start()
, execute()
, and finish()
. This structure is essential for operations on large data sets, ensuring that your application can scale efficiently.
global class MyBatchable implements Database.Batchable<sObject> { global Database.QueryLocator start(Database.BatchableContext BC) { // Query to fetch records for processing String query = 'SELECT Id, Name FROM Account'; return Database.getQueryLocator(query); } global void execute(Database.BatchableContext BC, List<Account> scope) { // Processing logic for each batch of records for (Account acc : scope) { // Example processing: updating the Account Name acc.Name = acc.Name + ' Processed'; } // Update processed records update scope; } global void finish(Database.BatchableContext BC) { // Any post-processing logic can go here } }
7. The Schedulable Interface: Automating Operations
For operations that need to occur on a schedule, Salesforce provides the Schedulable
interface. Implementing this interface in a class allows it to be scheduled either programmatically using the System.schedule
method or through the Salesforce UI.
global class MySchedulableClass implements Schedulable { global void execute(SchedulableContext sc) { // Your logic to be executed when the job is scheduled // This could be any Salesforce operations such as querying records, updating records, sending emails, etc. System.debug('Schedulable job executed at: ' + DateTime.now()); } }
Key Points in Scheduling
Understanding Cron
expressions is crucial for setting up schedules. This feature elevates the automation capabilities within Salesforce, allowing for regular data maintenance tasks, batch job initiations, or custom reminders.
String cronExp = '0 0 0 15 3 ? 2022'; // Example cron expression for running at midnight on the 15th of March 2022 MySchedulableClass scheduledJob = new MySchedulableClass(); System.schedule('My Scheduled Job', cronExp, scheduledJob);
8. The Messaging Class: Email and SMS Communications
Salesforce isn’t just about data; it’s also about communication. The Messaging
class provides methods for sending emails and SMS messages, enabling applications to communicate with users directly from within Salesforce.
Sending Emails Made Easy
- Creating
Messaging.SingleEmailMessage
instances, setting recipients, subject, and body, and then sending them withMessaging.sendEmail()
is a straightforward process for integrating email communications into your Salesforce applications.
// Create a new instance of Messaging.SingleEmailMessage Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage(); // Set the recipients of the email email.setToAddresses(new List<String>{'recipient@example.com'}); // Set the sender email address email.setReplyTo('sender@example.com'); email.setSenderDisplayName('Your Name'); // optional // Set the email subject email.setSubject('Example Subject'); // Set the email body email.setPlainTextBody('This is an example email body.'); // If you want to send HTML content, you can use setHtmlBody instead // email.setHtmlBody('<html><body><p>This is an example email body.</p></body></html>'); // Optionally, you can set additional email fields such as CC, BCC, etc. // email.setCcAddresses(new List<String>{'cc@example.com'}); // email.setBccAddresses(new List<String>{'bcc@example.com'}); // email.setFileAttachments(); // You can also attach files if needed // Send the email Messaging.sendEmail(new List<Messaging.SingleEmailMessage>{email});
9. The PageReference Class: Navigation and Redirection
Handling navigation within Salesforce is crucial for creating a seamless user experience. The PageReference
class provides methods for redirecting users to different pages or external URLs, ensuring that your application is both dynamic and user-friendly.
Implement Redirection
- Calling
PageReference
methods to set URLs, pass parameters, and redirect users can enhance the interactivity and navigability of your Salesforce applications.
public class MyController { // Method to navigate to a Visualforce page public PageReference goToPage() { // Create a new PageReference object and specify the page name PageReference pageRef = Page.MyVisualforcePage; // If you want to pass parameters to the page, you can use the getParameters() method pageRef.getParameters().put('param1', 'value1'); pageRef.getParameters().put('param2', 'value2'); // You can also set URL parameters directly // pageRef.getParameters().put('id', '001XXXXXXXXXXXXXXX'); // Return the PageReference object to navigate to the page return pageRef; } // Method to navigate to a Visualforce page with a specific record ID public PageReference goToPageWithRecordId(String recordId) { // Create a new PageReference object and specify the page name PageReference pageRef = Page.MyVisualforcePage; // Set the record ID as a parameter to pass to the page pageRef.getParameters().put('id', recordId); // Return the PageReference object to navigate to the page return pageRef; } // Method to redirect to another Visualforce page public void redirectToPage() { // Create a new PageReference object and specify the page name PageReference pageRef = Page.MyOtherVisualforcePage; // Use the setRedirect method to specify whether to redirect the user's browser // to the page (true) or just navigate to it without changing the URL (false) pageRef.setRedirect(true); // Navigate to the page if (!Test.isRunningTest()) { // Only perform the redirect if not running a test // (redirects are not allowed in test context) ApexPages.currentPage().setRedirect(true); ApexPages.currentPage().setPrevious(pageRef); } } }
In the example above:
goToPage()
method demonstrates how to navigate to a Visualforce page named “MyVisualforcePage” and pass parameters to it.goToPageWithRecordId(String recordId)
method demonstrates how to navigate to a Visualforce page and pass a record ID as a parameter.redirectToPage()
method demonstrates how to redirect to another Visualforce page named “MyOtherVisualforcePage”. Note that redirections can only be done in non-test contexts, so there’s a check for that.
10. The UserInfo Class: Accessing User Information
Personalizing applications and tailoring functionalities based on the current user can significantly enhance the user experience. The UserInfo
class offers methods to retrieve information about the current user, such as their language, profile, or permissions.
Personalization and Security
- Utilizing
UserInfo
methods allows for dynamic application behavior, ensuring that features and data are accessible according to the user’s privileges and preferences.
public class UserInfoExample { // Method to get the current user's ID public static Id getUserId() { return UserInfo.getUserId(); } // Method to get the current user's name public static String getUserName() { return UserInfo.getName(); } // Method to get the current user's profile ID public static Id getProfileId() { return UserInfo.getProfileId(); } // Method to get the current user's email public static String getUserEmail() { return UserInfo.getUserEmail(); } // Method to get the current user's language public static String getUserLanguage() { return UserInfo.getLanguage(); } // Method to get the current user's time zone public static String getUserTimeZone() { return UserInfo.getTimeZone().getID(); } // Method to get the current user's session ID public static String getSessionId() { return UserInfo.getSessionId(); } // Method to get the current user's organization ID public static String getOrganizationId() { return UserInfo.getOrganizationId(); } // Method to get the current user's organization name public static String getOrganizationName() { return UserInfo.getOrganizationName(); } }
Conclusion
The journey through Salesforce development is paved with myriad functionalities and customizations. Knowing your way around the essential Apex classes not only equips you with the tools needed for effective Salesforce development but also opens up a world of possibilities for creating tailored business solutions. Whether it’s managing data, automating processes, integrating external services, or communicating with users, these ten Apex classes provide a solid foundation for any developer looking to make their mark in the Salesforce landscape. So, roll up your sleeves, and let’s start coding!
Reference : Introducing Apex