Salesforce interview important topics
Salesforce interview important topics
1. Exceptions
2. Triggers
3. Testing
4. Async Apex
5. REST
6. Visualforce Basics
7. Development Lifecycle
Optional
1. Large Data Volumes
2. Single Sign On
3. Integration
4. Security
5. Siebel to Salesforce
6. Master Data Management
Exception Handling
Standard exception handling syntax - Order from Specific to Generic
try {
} catch(DmlException e) {
// DmlException handling code here.
} catch(Exception e) {
// Generic exception handling code here.
} finally {
// Final code goes here
}
pg. 1
o getCause: Returns the cause of the exception as an exception object.
o getLineNumber: Returns the line number from where the exception was
thrown.
o getMessage: Returns the error message that displays for the user.
o getStackTraceString: Returns the stack trace as a string.
o getTypeName: Returns the type of exception, such as DmlException,
ListException, MathException, and so on.
o Some exceptions such as DML exceptions have special methods
getDmlFieldNames - Returns the names of the fields that caused
the error for the specified failed record.
getDmlId: Returns the ID of the failed record that caused the
error for the specified failed record.
getDmlMessage: Returns the error message for the specified
failed record.
getNumDml: Returns the number of failed records.
// To create an exception
new MyException();
pg. 2
Triggers
Standard Trigger Syntax
o before insert
o before update
o before delete
o after insert
o after update
o after delete
o after undelete
Testing
Minimum 75% test coverage required to deploy to production
All tests must pass in order to deploy to production
@isTest annotation is put on the class to indicate that it is a test class
The test classes don't count towards the 3MB org code size limit
Test methods need to be static and are defined using the testmethod keyword
or with the @isTest annotation
or
The tests can have only one Test.startTest() and Test.stopTest() block. This
block ensures that other setup code in your test doesn’t share the same limits
and enables you to test the governor limits.
pg. 3
Async Apex
Scheduable
Used to run apex code at specific times
Uses the Scheduable interface which requires that the execute function be
implemented
Example:
When Test.StartTest() is used then the job run immediately instead of waiting
for Cron time.
You can only have 100 classes scheduled at one time.
The Scheduled Jobs setup item can be used to find currently scheduled jobs
pg. 4
Example:
global CleanUpRecords(String q) {
query = q;
}
// The execute method is called for each batch of records passed to the
method. Use this method to do all required processing for each chunk of data.
global void execute(Database.BatchableContext BC, List<sObject> scope){
delete scope;
Database.emptyRecycleBin(scope);
}
// The finish method is called after all batches are processed. Use this
method to send confirmation emails or execute post-processing operations.
global void finish(Database.BatchableContext BC){
AsyncApexJob a =
[SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
TotalJobItems, CreatedBy.Email
FROM AsyncApexJob WHERE Id =
:BC.getJobId()];
// Send an email to the Apex job's submitter
// notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {a.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('Record Clean Up Status: ' + a.Status);
mail.setPlainTextBody
('The batch Apex job processed ' + a.TotalJobItems +
' batches with '+ a.NumberOfErrors + ' failures.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
Batches of records are not guaranteed to execute in the order they are
received from the start method.
The maximum number of records that can be returned in the
Database.QueryLocator object is 50 million.
Test methods can execute only one batch.
To execute a batch job use Database.executeBatch
pg. 5
TotalJobItems, CreatedBy.Email
FROM AsyncApexJob WHERE Id = :BatchId];
Future Methods
Used to run Apex asynchronously in its own thread at a later time when system
resources become available.
You use the @future annotation to identify methods that run asynchronously
Future Methods must be Static
Can only return Void Type
Can't call one future method from another
Can't take Standard or Custom Data Types as arguments (Typiccally, we use
'ID' or 'List' as arguments for processing records)
Typically used for Callouts to external Web services, Non-Immediate Resource
intensive operations.
Queueable Apex
Is Similar to Future Methods but with some extra features.To use Queueable Apex,
simply implement the Queueable interface.
pg. 6
ID jobID = System.enqueueJob(updateJob);
SELECT Id, Status, NumberOfErrors FROM AsyncApexJob WHERE Id = :jobID // Monitor
it
REST
To create a rest resource annotate the class
with @RestResource(urlMapping='/Accounts/*
The base URL is https://instance.salesforce.com/services/apexrest/ and the rest
of the mapping is appended to that.
Class must be global and the methods must be global static
The @HttpGet or @HttpPost annotations need to be used on the methods
Use the following to get the compelete URL of the request
In the above example we are splitting the URL and taking the last index
@HttpPost
global static String createMerchandise(String name,
String description, Decimal price, Double inventory) {
Merchandise c m = new Merchandise c(
Name=name,
Description c=description,
Price c=price,
Total_Inventory c=inventory);
insert m;
return m.Id;
}
{
"name" : "Eraser",
"description" : "White eraser",
"price" : 0.75,
"inventory" : 1000
}
Visualforce Basics
pg. 7
In order to use a Standard List controller, add the recordSetVar attribute to
the <apex:page> tag
The <apex:pageBlock/> and <apex:pageBlockSection /> tags create some user
interface elements which match the standard UI style
The pageBlockSection tag has a columns element which lets you set the
number of columns in the section.
The <apex:pageBlockTable value="{!products}" var="pitem"> tag adds the
standard visualforce table.
The column tag creates a column in the table
The tabStyle attribute of apex:page will make sure that the tab is displayed as
the Object Name when a standardController is not used
The $User variable is used to access user details
The <apex:detail /> tag is used to display the standard view page for a record
The relatedList tag is used to display related lists
<apex:outputLink value="{!URLFOR($Action.Account.new)}">Create</apex:outputLink>
</apex:page>
* Use the template by using the ```<apex:define />``` tag
pg. 8
```html
<apex:page sidebar="false" showHeader="false">
<apex:composition template="BasicTemplate">
<apex:define name="body">
<p>This is a simple page demonstrating that this
text is substituted, and that a banner is created.</p>
</apex:define>
</apex:composition>
</apex:page>
o Another way to include a page is to use the <apex:include /> tag
<apex:page sidebar="false" showHeader="false"> <p>Test Before</p>
<apex:include pageName="MainPage"/> <p>Test After</p>
</apex:page>
<apex:outputText value="{0,number,currency}">
<apex:param value="{!pitem.Price}"/>
</apex:outputText>
Development Lifecycle
Typical Development Lifecycle for Developing in Production
o Change Sets
o ANT Migration Toolkit
pg. 9
o Force.com IDE
Types of Sandboxes
pg. 10
documents, and attachments. Use the sandbox to code and test
changes, and to train your team about the changes. You can refresh a
Full sandbox every 29 days.
Uses of Sandboxes
pg. 11
o Schedule your concurrent development projects. This will help you
determine if the new functionality can be done now, in the current
release, or sometime in the future.
o Establish a process for changes to the production organization.
o Track changes in all environments. This will ensure that short-term
functionality that is delivered to production does not get overwritten
when you deploy from your development environment.
o Integrate changes and deploy to staging or test environments.
o Release to production.
o Determines the best index from which to drive the query, if possible,
based on filters in the query
o Determines the best table to drive the query from if no good index is
available
o Determines how to order the remaining tables to minimize cost
o Injects custom foreign key value tables as needed to create efficient
join paths
o Influences the execution plan for the remaining joins, including sharing
joins, to minimize database input/output (I/O)
o Updates statistics
Skinny Tables -
o These are copies of the data for a table with limited number of fields
(100 columns).
o Are kept in sync with the source data
o Help in fast data access.
o Can only contain field from the base object
o Need to be enabled by support
Indexes
pg. 12
o Indexes for External Id are created by default
o By default nulls are not considered in the index
o If a where clause narrows down the crietria to 30% for Standard fields
or 10% for Custom fields the index is used
o Formula fields which are deterministic are indexed
o A formula field is deterministic if
It does not use TODAY(), NOW(), etc
Does not refer to a different object
Does not refer to a formula field which references a different
object
Owner field
Standard field with special functionalities
o Two column indexes can also be created for supporting search + sort.
These are more efficient than 2 indexes.
Mashups can be used to get real time data from an external system by either
using Canvas or Callouts
Hard Deletes can be used to optimize performance so that data does not go
to the recycle bin.
o Partition data
o Minimize no of joins (No of objects and relationships on the report)
o Reduce amount of data returned - reduce no of fields
o Use filters which use standard or custom indexes
o Archive unused records
o Use the bulk api if you have more than 100,000 records
o insert() is the fastest followed bu update() and then upsert()
o Data should be clean before processing. Error in batches cause the
records to be processed row by row.
o Load only changed data
o For Custom integrations - use http keep-alive, use gzip compression,
authenticate only once
pg. 13
o Avoid switching on sharing during the load
o Disable Computations such as Apex Triggers, Workflows, etc
o Group records by ParentId to avoid locking conflicts
o Use SF Guid instead of External Id for Parent References
o Bulk API has a limit of the number of records you can load in a day. 300
batches and 10,000 records per batch
o Avoid Wildcards
o Reduce the no of joins
o Partition data with Divisions
Single Sign On
Preferred method is Standards based SAML
pg. 14
Best way is to use the My Domain Feature
Supports mutiple identity providers
IDP Sends single sign on messages
A Service Provider (SP) recieves Single Sign On messages
Trust is stablished by exchanging meta data
Messages are digitaly signed XML documents
Single Sign on works on mobile and desktop app as well when using OAuth
Issuer is a unique string in the SAML
IDP Certificate is used to validate the signed request
Three subjects are supported
o Salesforce.com username
o Federation Id
o User Id from User object
IDP must support relay state for SP initiated SAML
Just in time provisioning allows the IDP to create a user in Salesforce, requires
to pass provisioning attributes
Single Sign On is possible for Communities and Portal
Firefox has a SAML Tracer plugin to debug or the SAML Assertion validator
Salesforce Identity
Use connected apps to connect to external apps
Social Sign On
Login and OAuth access from public sources
Use from My Domains features
Supported Providers
o Salesforce
o Facebook
o Open Id Connect
o Janrain
Registration handler class is used to create, update or link to existing users
Integration
pg. 15
The following are useful tips when coming up with a end state architecture
Typical methods
Security
Authentication
Authorisation
pg. 16
Salesforce to Siebel
1. Vision
2. KPIS -
3. Define Capabilities
o Coexitance
o Methodical
5. Map Entities
o Don't replicate
6. Design Application
o Data Model
o Logic/Workflows
7. Design Integration
8. Change Management
9. Implement
10. Rollout
pg. 17
Data Migration Framework
1. Right Data Architecture - End to end architecture
2. Legacy Data Analysis - Understand History, Identify Data quality issues. Define
Archival, Purge strategy
3. Data Readyness - Standarisation, Enrichment, Transformtion. Conduct one
time cleanup
4. Comprehensive Testing and Verfication - Use reports, Test for consitency,
usability
5. Training and Deployment
Why
pg. 18
o Accurate Reporting
Patterns of Integration
How
Implementional Approaches
Data Stewardship
MDM and CRM complement each other. CRM enables MDM to create better
master data. MDM provides better visibility to CRM related data.
pg. 19
Platform Development Basics
Reference
Platform Development Basics
Salesforce Platform
Like any platform, the Salesforce platform is a group of technologies that
supports the development of other technologies on top of it. What makes it
unique is that the platform supports not only all the Salesforce clouds, but it
also supports custom functionality built by our customers and partners. This
functionality ranges from simple page layouts to full-scale applications.
Core Platform
The core platform lets you develop custom data models and applications for
desktop and mobile. And with the platform behind your development, you
can build robust systems at a rapid pace.
Heroku Platform
Heroku gives developers the power to build highly scalable web apps and
back-end services using Python, Ruby, Go, and more. It also provides database
tools to sync seamlessly with data from Salesforce.
Salesforce APIs
These let developers integrate and connect all their enterprise data, networks,
and identity information.
Mobile SDK
The Mobile SDK is a suite of technologies that lets you build native, HTML5,
and hybrid apps that have the same reliability and security as the Salesforce
app.
pg. 20
Metadata-driven development model
the key differences between developing on the platform and developing
outside of Salesforce. Because the platform is metadata-aware, it can auto-
generate a significant part of your user experience for you.
Things like dialogs, record lists, detail views, and forms that you’d normally
have to develop by yourself come for free.
You even get all the functionality to create, read, update, and delete
(affectionately referred to as CRUD) custom object records in the database.
Apex
Salesforce’s proprietary programming language with Java-like syntax.
Visualforce
A markup language that lets you create custom Salesforce pages with code
that looks a lot like HTML, and optionally can use a powerful combination of
Apex and JavaScript.
Data Security
Reference
Data Security
For your whole org, you can maintain a list of authorized users, set password policies,
and limit logins to certain hours and locations.
2. Objects
pg. 21
Access to object-level data is the simplest thing to control. By setting permissions on
a particular type of object, you can prevent a group of users from creating, viewing,
editing, or deleting any records of that object.
For example, you can use object permissions to ensure that interviewers can view
positions and job applications but not edit or delete them.
3. Fields
You can restrict access to certain fields, even if a user has access to the object.
For example, you can make the salary field in a position object invisible to
interviewers but visible to hiring managers and recruiters.
4. Records
You can allow particular users to view an object, but then restrict the individual object
records they're allowed to see.
For example, an interviewer can see and edit her own reviews, but not the reviews of
other interviewers. You can manage record-level access in these four ways.
Manage Users
o Create User
o Deactivate a User
o Set Password Policy
o Restrict Login Access by IP Address
o Restrict Login Access by Time
pg. 22
Manage Object Permissions
The simplest way to control data access is to set permissions on a particular
type of object. (An object is a collection of records, like leads or contacts.) You
can control whether a group of users can create, view, edit, or delete any
records of that object.
You can set object permissions with profiles or permission sets. A user can
have one profile and many permission sets.
o A user’s profile determines the objects they can access and the things they
can do with any object record (such as create, read, edit, or delete).
o Permission sets grant additional permissions and access settings to a user.
Use profiles to grant the minimum permissions and settings that all users of a
particular type need. Then use permission sets to grant more permissions as
needed. The combination of profiles and permission sets gives you a great
deal of flexibility in specifying object-level access.
Each user has a single profile that controls which data and features that user
has access to. A profile is a collection of settings and permissions. Profile
settings determine which data the user can see, and permissions determine
what the user can do with that data.
o The settings in a user’s profile determine whether she can see a particular app,
tab, field, or record type.
o The permissions in a user’s profile determine whether she can create or edit
records of a given type, run reports, and customize the app.
Profiles usually match up with a user's job function (for example, system
administrator, recruiter, or hiring manager), but you can have profiles for
anything that makes sense for your Salesforce org. A profile can be assigned
to many users, but a user can have only one profile at a time.
Standard Profiles
Read Only
Standard User
Marketing User
Contract Manager
System Administrator
pg. 23
Permission Sets
A permission set is a collection of settings and permissions that give users
access to various tools and functions. The settings and permissions in
permission sets are also found in profiles, but permission sets extend users’
functional access without changing their profiles.
Permission sets make it easy to grant access to the various apps and custom
objects in your org, and to take away access when it’s no longer needed.
Users can have only one profile, but they can have multiple permission sets.
You'll be using permission sets for two general purposes: to grant access to
custom objects or apps, and to grant permissions—temporarily or long
term—to specific fields.
Defining field-level security for sensitive fields is the second piece of the security and
sharing puzzle, after controlling object-level access.
Record-Level Security
Record access determines which individual records users can view and edit in
each object they have access to in their profile. First ask yourself these
questions:
o Should your users have open access to every record, or just a subset?
o If it’s a subset, what rules should determine whether the user can access
them?
pg. 24
You control record-level access in four ways. They’re listed in order of
increasing access. You use org-wide defaults to lock down your data to the
most restrictive level, and then use the other record-level security tools to
grant access to selected users, as required.
i. Org-wide defaults - specify the default level of access users have to each other’s
records.
ii. Role hierarchies - ensure managers have access to the same records as their
subordinates. Each role in the hierarchy represents a level of data access that
a user or group of users needs.
iii. Sharing rules - are automatic exceptions to org-wide defaults for particular
groups of users, to give them access to records they don’t own or can’t
normally see.
iv. Manual sharing - lets record owners give read and edit permissions to users
who might not have access to the record any other way.
Role Hierarchy
A role hierarchy works together with sharing settings to determine the levels of
access users have to your Salesforce data. Users can access the data of all the users
directly below them in the hierarchy.
Sharing Rules
This enables you to make automatic exceptions to your org-wide sharing settings for
selected sets of users.
Sharing rules can be based on who owns the record or on the values of fields in the
record. For example, use sharing rules to extend sharing access to users in public
groups or roles. As with role hierarchies, sharing rules can never be stricter than your
org-wide default settings. They just allow greater access for particular users.
Public Group
Using a public group when defining a sharing rule makes the rule easier to create
and, more important, easier to understand later, especially if it's one of many sharing
rules that you're trying to maintain in a large organization.
Create a public group if you want to define a sharing rule that encompasses more
than one or two groups or roles, or any individual.
pg. 25
Reference
Formulas & Validations
Formula Fields
Fields that have calculated values based on a Formula which is entered in the Formula
Editor.
You can create custom formula fields on any standard or custom object.
Always use the Check Syntax button
o Check Syntax button in the editor is an important tool for debugging your
formulas.
o The syntax checker tells you what error it encountered and where it’s located
in your formula.
You can create roll-up summary fields that automatically display a value on a
master record based on the values of records in a detail record. These detail
records must be directly related to the master through a master-detail
relationship
You can perform different types of calculations with roll-up summary fields.
You can count the number of detail records related to a master record, or
calculate the sum, minimum value, or maximum value of a field in the detail
records. For example, you might want:
o A custom account field that calculates the total of all related pending
opportunities.
o A custom order field that sums the unit prices of products that contain a
description you specify.
pg. 26
o MAX - Displays the highest value of the field you select in the Field to
Aggregate option for all directly related records. Only number, currency,
percent, date, and date/time fields are available.
Validation Rules
Validation rules verify that data entered by users in records meet the standards you
specify before they can save it.
A validation rule can contain a formula or expression that evaluates the data in one or
more fields and returns a value of “True” or “False.”
Validation rules can also include error messages to display to users when they enter
invalid values based on specified criteria. Using these rules effectively contributes to
quality data.
For example, you can ensure that all phone number fields contain a specified format
or that discounts applied to certain products never exceed a defined percentage.
Lightning Flow
Lightning Flow provides declarative process automation for every Salesforce app,
experience, and portal. Included in Lightning Flow are two point-and-click
automation tools: Process Builder and Cloud Flow Designer.
Reference
Lightning Flow
Process Builder
A simple but versatile tool for automating simple business processes. In Process
Builder, you build processes.
Process Builder is the simplest Lightning Flow tool for the job.
For a given object, Process Builder lets you control the order of your business
processes without any code.
pg. 27
Cloud Flow Designer
A drag-and-drop tool for building more complex business processes. In the Cloud
Flow Designer, you build flows.
In Cloud Flow Designer, you can’t define a trigger. For a flow to start automatically,
you have to call it from something else, like a process or Apex trigger.
Business processes that need input from users, whether they’re employees or
customers.
Use Cloud Flow Designer - If the business process you’re automating requires user
input, use the Cloud Flow Designer to build a flow. That way, you can provide a rich,
guided experience for your users, whether in your Salesforce org or in a Lightning
community.
Behind-the-scenes automation
Business processes that get all the necessary data from your Salesforce org or a
connected system. In other words, user input isn’t needed.
Use Process Builder Most behind-the-scenes business processes are designed to
start automatically when a particular thing occurs. Generally, we refer to that “thing”
as a trigger. Business processes can be automatically triggered when:
o A record changes
o A platform event message is received
o A certain amount of time passes or specified time is reached
Approval automation
Business processes that determine how a record, like a time-off request, gets
approved by the right stakeholders.
To automate your company’s business processes for approving records, use
Approvals to build an approval process.
pg. 28
In a nutshell: Process Builder vs Cloud Flow Designer vs Approval
Automation
Process Builder and Cloud Flow Designer are Lightning Flow tools. Approval
Automation is just an additional tool.
Cloud Flow Designer is like a workflow which may or may not requires human
input. (e.g. Screen flows requires human input, Autolaunches flows do not )
Process Builder
Process Builder is a point-and-click tool that lets you easily automate if/then
business processes and see a graphical representation of your process as you
build.
Every process consists of a trigger, at least one criteria node, and at least one
action. You can configure immediate actions or schedule actions to be
executed at a specific time.
o Each immediate action is executed as soon as the criteria evaluates to true.
o Each scheduled action is executed at the specified time, such as 10 days
before the record’s close date or 2 days from now.
Process Types
pg. 29
Flow Building Blocks
1. Elements - appear on the canvas. To add an element to the canvas, drag it there from
the palette.
2. Connectors - define the path that the flow takes at runtime. They tell the flow which
element to execute next.
3. Resources - are containers that represent a given value, such as field values or
formulas. You can reference resources throughout your flow. For example, look up an
account’s ID, store that ID in a variable, and later reference that ID to update the
account.
Flow Elements
1. Screen - Display data to your users or collect information from them with
Screen elements. You can add simple fields to your screens, like input fields
and radio buttons and out-of-the-box Lightning components like File Upload
2. Logic - Control the flow of... well, your flow. Create branches, update data,
loop over sets of data, or wait for a particular time.
3. Actions - Do something in Salesforce when you have the necessary
information (perhaps collected from the user via a screen). Flows can look up,
create, update, and delete Salesforce records. They can also create Chatter
posts, submit records for approval, and send emails. If your action isn’t
possible out of the box, call Apex code from the flow.
4. Integrations - In addition to connecting with external systems by calling Apex
code, the Cloud Flow Designer has a couple of tie-ins to platform events.
Publish platform event messages with a Record Create element. Subscribe to
platform events with a Wait element.
Flow Variables
Approvals
An approval process automates how Salesforce records are approved in your org. In
an approval process, you specify:
pg. 30
o The steps necessary for a record to be approved and who approves it at each
step.
o The actions to take based on what happens during the approval process.
What is Apex?
Apex is a programming language that uses Java-like syntax and acts like
database stored procedures.
pg. 31
Apex Data Types
Primitives
Integer
Double
Long
Date
Datetime
String
ID
Boolean
sObject
Collections
List
Set
Map
Enum
pg. 32
DML Statements
insert
update
upsert
o DML operation creates new records and updates sObject records within a
single statement, using a specified field to determine the presence of existing
objects, or the ID field if no field is specified.
delete
undelete
merge
o merges up to three records of the same sObject type into one of the records,
deleting the others, and re-parenting any related records.
Insert Records
// Create the account sObject
Account acct = new Account(Name='Acme', Phone='(415)555-1212',
NumberOfEmployees=100);
// Insert the account by using DML
insert acct;
Bulk DML
You can perform DML operations either on a single sObject, or in bulk on a list of
sObjects.
Performing bulk DML operations is the recommended way because it helps avoid
hitting governor limits, such as the DML limit of 150 statements per Apex transaction.
Upsert Records
// Insert the Josh contact
pg. 33
Contact josh = new
Contact(FirstName='Josh',LastName='Kaplan',Department='Finance');
insert josh;
// Josh's record has been inserted
// so the variable josh has now an ID
// which will be used to match the records by upsert
josh.Description = 'Josh\'s record has been updated by the upsert operation.';
// Create the Kathy contact, but don't persist it in the database
Contact kathy = new
Contact(FirstName='Kathy',LastName='Brown',Department='Technology');
// List to hold the new contacts to upsert
List<Contact> contacts = new List<Contact> { josh, kathy };
// Call upsert
upsert contacts;
// Result: Josh is updated and Kathy is created.
Delete Records
Contact[] contactsDel = [SELECT Id FROM Contact WHERE LastName='Smith'];
delete contactsDel;
DML Exception
try {
// This causes an exception because
// the required Name field is not provided.
Account acct = new Account();
// Insert the account
insert acct;
} catch (DmlException e) {
System.debug('A DML exception has occurred: ' +
e.getMessage());
}
pg. 34
Database Methods
Apex contains the built-in Database class, which provides methods that
perform DML operations and mirror the DML statement counterparts.
o Database.insert()
o Database.update()
o Database.upsert()
o Database.delete()
o Database.undelete()
o Database.merge()
Unlike DML statements, Database methods have an
optional allOrNone parameter that allows you to specify whether the operation
should partially succeed. When this parameter is set to false, if errors occur on
a partial set of records, the successful records will be committed and errors
will be returned for the failed records. Also, no exceptions are thrown with the
partial success option.
By default, the allOrNone parameter is true, which means that the Database method
behaves like its DML statement counterpart and will throw an exception if a failure is
encountered.
Database.SaveResult
Database.SaveResult[] results = Database.insert(recordList, false);
pg. 35
System.debug('Successfully inserted contact. Contact ID: ' + sr.getId());
} else {
// Operation failed, so get all errors
for(Database.Error err : sr.getErrors()) {
System.debug('The following error has occurred.');
System.debug(err.getStatusCode() + ': ' + err.getMessage());
System.debug('Contact fields that affected this error: ' +
err.getFields());
}
}
}
Use DML statements if you want any error that occurs during bulk DML
processing to be thrown as an Apex exception that immediately interrupts
control flow (by using try. . .catch blocks). This behavior is similar to the way
exceptions are handled in most database procedural languages.
Use Database class methods if you want to allow partial success of a bulk DML
operation — if a record fails, the remainder of the DML operation can still
succeed. Your application can then inspect the rejected records and possibly
retry the operation. When using this form, you can write code that never
throws DML exception errors. Instead, your code can use the appropriate
results array to judge success or failure. Note that Database methods also
include a syntax that supports thrown exceptions, similar to DML statements.
pg. 36
queriedContact.Phone = '(415)555-1213';
// Update the related account industry
queriedContact.Account.Industry = 'Technology';
// Make two separate calls
// 1. This call is to update the contact's phone.
update queriedContact;
// 2. This call is to update the related account's Industry field.
update queriedContact.Account;
Because Apex has direct access to Salesforce records that are stored in the
database, you can embed SOQL queries in your Apex code and get results in a
straightforward fashion. When SOQL is embedded in Apex, it is referred to as
inline SOQL.
Inline SOQL
Account[] accts = [SELECT Name,Phone FROM Account];
pg. 37
Query Editor
The Developer Console provides the Query Editor console, which enables you to run
your SOQL queries and view results. The Query Editor provides a quick way to inspect
the database. It is a good way to test your SOQL queries before adding them to your
Apex code. When you use the Query Editor, you need to supply only the SOQL
statement without the Apex code that surrounds it.
pg. 38
// Write all account array info
System.debug(accts);
pg. 39
Salesforce Object Search Language (SOSL)
a Salesforce search language that is used to perform text searches in records. Use
SOSL to search fields across multiple standard and custom object records in
Salesforce. SOSL is similar to Apache Lucene.
Inline SOSL
List<List<SObject>> searchList = [FIND 'SFDC' IN ALL FIELDS
RETURNING Account(Name),
Contact(FirstName,LastName)];
SOQL vs SOSL
Like SOQL, SOSL allows you to search your organization’s records for specific
information.
Unlike SOQL, which can only query one standard or custom object at a time, a single
SOSL query can search all objects.
Another difference is that SOSL matches fields based on a word match while SOQL
performs an exact match by default (when not using wildcards). For example,
searching for 'Digital' in SOSL returns records whose field values are 'Digital' or 'The
Digital Company', but SOQL returns only records with field values of 'Digital'.
Use SOQL to retrieve records for a single object.
Use SOSL to search fields across multiple objects. SOSL queries can search most text
fields on an object.
Query Editor
The Developer Console provides the Query Editor console, which enables you to run
SOSL queries and view results. The Query Editor provides a quick way to inspect the
database. It is a good way to test your SOSL queries before adding them to your
Apex code. When you use the Query Editor, you need to supply only the SOSL
statement without the Apex code that surrounds it.
pg. 40
zero or more characters at the middle or end of the search term. The ?
wildcard matches only one character at the middle or end of the search term.
pg. 41
Contact and Lead Search Challenge
public class ContactAndLeadSearch {
public static List<List<sObject>> searchContactsAndLeads(String
nameParam) {
List<List<sObject>> nameList = [FIND :nameParam IN NAME FIELDS
RETURNING Contact(FirstName,LastName),Lead(Name)];
System.debug(nameList);
return nameList;
}
}
Apex Triggers
Apex triggers enable you to perform custom actions before or after events to records
in Salesforce, such as insertions, updates, or deletions. Just like database systems
support triggers, Apex provides trigger support for managing records.
Reference
Apex Trigger
Triggers
Invoking Callouts Using Apex
Apex Callouts
Trigger Syntax
trigger TriggerName on ObjectName (trigger_events) {
code_block
}
Trigger Events
o before insert
o before update
o before delete
o after insert
o after update
o after delete
o after undelete
pg. 42
Sample Trigger on Account Creation
trigger HelloWorldTrigger on Account (before insert) {
System.debug('Hello World!');
}
Types of Triggers
Before triggers
are used to update or validate record values before they’re saved to the database.
After triggers
are used to access field values that are set by the system (such as a record's Id or
LastModifiedDate field), and to affect changes in other records. The records that fire
the after trigger are read-only.
Context Variables
Trigger.New contains all the records that were inserted in insert or update triggers.
Trigger.Old provides the old version of sObjects before they were updated in
update triggers, or a list of deleted sObjects in delete triggers.
Iterate over each account in a for loop and update the Description
field for each.
trigger HelloWorldTrigger on Account (before insert) {
for(Account a : Trigger.New) {
a.Description = 'New description';
}
}
The system saves the records that fired the before trigger after the trigger finishes
execution. You can modify the records in the trigger without explicitly calling a DML
insert or update operation. If you perform DML statements on those records, you get
an error.
pg. 43
Boolean Context Variables
trigger ContextExampleTrigger on Account (before insert, after insert, after
delete) {
if (Trigger.isInsert) {
if (Trigger.isBefore) {
// Process before insert
} else if (Trigger.isAfter) {
// Process after insert
}
}
else if (Trigger.isDelete) {
// Process after delete
}
}
isExecuting Returns true if the current context for the Apex code is a trigger, not a
Visualforce page, a Web service, or an executeanonymous() API call.
isInsert Returns true if this trigger was fired due to an insert operation, from the
Salesforce user interface, Apex, or the API.
isUpdate Returns true if this trigger was fired due to an update operation, from the
Salesforce user interface, Apex, or the API.
isDelete Returns true if this trigger was fired due to a delete operation, from the
Salesforce user interface, Apex, or the API.
isBefore Returns true if this trigger was fired before any record was saved.
isAfter Returns true if this trigger was fired after all records were saved.
isUndelete Returns true if this trigger was fired after a record is recovered from the
Recycle Bin (that is, after an undelete operation from the Salesforce user interface,
Apex, or the API.)
new Returns a list of the new versions of the sObject records.
o This sObject list is only available in insert, update, and undelete triggers, and
the records can only be modified in before triggers.
This map is only available in before update, after insert, after update, and after
undelete triggers.
size The total number of records in a trigger invocation, both old and new.
pg. 44
Calling a Class Method from a Trigger
trigger ExampleTrigger on Contact (after insert, after delete) {
if (Trigger.isInsert) {
Integer recordCount = Trigger.New.size();
// Call a utility method from another class
EmailManager.sendMail('Your email address', 'Trailhead Trigger Tutorial',
recordCount + ' contact(s) were inserted.');
}
else if (Trigger.isDelete) {
// Process after delete
}
}
Trigger Exception
trigger AccountDeletion on Account (before delete) {
pg. 45
}
Apex allows you to make calls to and integrate your Apex code with external Web
services. Apex calls to external Web services are referred to as callouts.
For example, you can make a callout to a stock quote service to get the latest quotes.
When making a callout from a trigger, the callout must be done asynchronously so
that the trigger process doesn’t block you from working while waiting for the external
service's response.The asynchronous callout is made in a background process, and
the response is received when the external service returns it.
Sample Callout
public class CalloutClass {
@future(callout=true)
public static void makeCallout() {
HttpRequest request = new HttpRequest();
// Set the endpoint URL.
String endpoint = 'http://yourHost/yourService';
request.setEndPoint(endpoint);
// Set the HTTP verb to GET.
request.setMethod('GET');
// Send the HTTP request and get the response.
HttpResponse response = new HTTP().send(request);
}
}
pg. 46
Bulk Apex Triggers
When you use bulk design patterns, your triggers have better performance,
consume less server resources, and are less likely to exceed platform limits.
The benefit of bulkifying your code is that bulkified code can process large
numbers of records efficiently and run within governor limits on the Lightning
Platform. These governor limits are in place to ensure that runaway code
doesn’t monopolize resources on the multitenant platform.
Not Bulk
trigger MyTriggerNotBulk on Account(before insert) {
Account a = Trigger.New[0];
a.Description = 'New description';
}
Use this to avoid Query limits which are 100 SOQL queries for synchronous Apex or
200 for asynchronous Apex.
Bad Practice
trigger SoqlTriggerNotBulk on Account(after update) {
for(Account a : Trigger.New) {
// Get child records for each account
// Inefficient SOQL query as it runs once for each account!
Opportunity[] opps = [SELECT Id,Name,CloseDate
FROM Opportunity WHERE AccountId=:a.Id];
pg. 47
Good Practice
pg. 48
Bulk DML
Use this because the Apex runtime allows up to 150 DML calls in one transaction.
Bad Practice
trigger DmlTriggerNotBulk on Account(after update) {
// Get the related opportunities for the accounts in this trigger.
List<Opportunity> relatedOpps = [SELECT Id,Name,Probability FROM Opportunity
WHERE AccountId IN :Trigger.New];
// Iterate over the related opportunities
for(Opportunity opp : relatedOpps) {
// Update the description when probability is greater
// than 50% but less than 100%
if ((opp.Probability >= 50) && (opp.Probability < 100)) {
opp.Description = 'New description for opportunity.';
// Update once for each opportunity -- not efficient!
update opp;
}
}
}
Good Practice
Store records to a list first before updating. Don't update per record.
Instead of checking an opportunities list size for each record in the loop, add the
condition in the main query.
pg. 49
List<Opportunity> oppList = new List<Opportunity>();
if (oppList.size() > 0) {
insert oppList;
}
}
WHERE Id IN :Trigger.New
WhatId = o.Id));
}
if(taskList.size() > 0) {
insert taskList;
}
}
Apex Testing
pg. 50
The Apex testing framework enables you to write and execute tests for your Apex
classes and triggers on the Lightning Platform platform. Apex unit tests ensure high
quality for your Apex code and let you meet requirements for deploying Apex.
Reference
Apex Testing
Using the isTest annotation instead of the testMethod keyword is more flexible as
you can specify parameters in the annotation.
Visibility of a test method doesn’t matter, so declaring a test method as public or
private doesn’t make a difference.
Test classes can be either private or public. If you’re using a test class for unit
testing only, declare it as private. Public test classes are typically used for test data
factory classes.
@isTest
private class MyTestClass {
@isTest static void myTest() {
// code_block
}
}
Temperature Converter
public class TemperatureConverter {
pg. 51
// Takes a Fahrenheit temperature and returns the Celsius equivalent.
public static Decimal FahrenheitToCelsius(Decimal fh) {
Decimal cs = (fh - 32) * 5/9;
return cs.setScale(2);
}
}
pg. 52
}
String taskPriority;
if (leadState == 'CA') {
taskPriority = 'High';
} else {
taskPriority = 'Normal';
}
return taskPriority;
}
}
100% Coverage
@isTest
private class TaskUtilTest {
@isTest static void testTaskPriority() {
String pri = TaskUtil.getTaskPriority('NY');
System.assertEquals('Normal', pri);
}
pg. 53
public class VerifyDate {
TestVerifyDate class
@istest
private class TestVerifyDate {
AccountDelation class
TestAccountDeletion class
@isTest
private class TestAccountDeletion {
@isTest static void TestDeleteAccountWithOneOpportunity() {
// Test data setup
// Create an account with an opportunity, and then try to delete it
Account acct = new Account(Name='Test Account');
insert acct;
Opportunity opp = new Opportunity(Name=acct.Name + ' Opportunity',
StageName='Prospecting',
CloseDate=System.today().addMonths(1),
AccountId=acct.Id);
insert opp;
// Perform test
Test.startTest();
Database.DeleteResult result = Database.delete(acct, false);
Test.stopTest();
// Verify
// In this case the deletion should have been stopped by the trigger,
// so verify that we got back an error.
System.assert(!result.isSuccess());
pg. 55
System.assert(result.getErrors().size() > 0);
System.assertEquals('Cannot delete account with related opportunities.',
result.getErrors()[0].getMessage());
}
}
Test.startTest() and Test.stopTest()
The test method contains the Test.startTest() and Test.stopTest() method pair, which
delimits a block of code that gets a fresh set of governor limits. In this test, test-data
setup uses two DML statements before the test is performed.
The startTest method marks the point in your test code when your test actually
begins. Each test method is allowed to call this method only once. All of the code
before this method should be used to initialize variables, populate data structures,
and so on, allowing you to set up everything you need to run your test. Any code that
executes after the call to startTest and before stopTest is assigned a new set of
governor limits.
RestrictContactByName class
}
}
TestRestrictContactByName class
// Perform test
try {
insert givenContact;
}
catch(DmlException e) {
pg. 56
//Assert Error Message
System.assert(
e.getMessage().contains('The Last Name
"'+givenLastName+'" is not allowed for DML'),
e.getMessage()
);
//Assert Field
System.assertEquals(Contact.LastName, e.getDmlFields(0)[0]);
// Perform test
try {
Test.startTest();
insert givenContact;
Contact[] resultContacts = [SELECT LastName FROM Contact
WHERE LastName=:givenLastName];
Test.stopTest();
// Verify
System.assertEquals(resultContacts[0].LastName,
givenLastName);
}
catch(DmlException e) {
//Assert Error Message
System.assert(
String.isEmpty(e.getMessage()),
e.getMessage()
);
}
}
}
TestDataFactory class
@isTest
public class TestDataFactory {
public static List<Account> createAccountsWithOpps(Integer numAccts, Integer
numOppsPerAcct) {
pg. 57
List<Account> accts = new List<Account>();
for(Integer i=0;i<numAccts;i++) {
Account a = new Account(Name='TestAccount' + i);
accts.add(a);
}
insert accts;
return accts;
}
}
// Perform test
Test.startTest();
Database.DeleteResult result = Database.delete(accts[0], false);
Test.stopTest();
// Verify
// In this case the deletion should have been stopped by the trigger,
// so verify that we got back an error.
System.assert(!result.isSuccess());
System.assert(result.getErrors().size() > 0);
System.assertEquals('Cannot delete account with related opportunities.',
result.getErrors()[0].getMessage());
}
// Perform test
Test.startTest();
Database.DeleteResult result = Database.delete(accts[0], false);
Test.stopTest();
pg. 58
// Verify that the deletion was successful
System.assert(result.isSuccess(), result);
}
// Perform test
Test.startTest();
Database.DeleteResult[] results = Database.delete(accts, false);
Test.stopTest();
// Verify for each record.
// In this case the deletion should have been stopped by the trigger,
// so check that we got back an error.
for(Database.DeleteResult dr : results) {
System.assert(!dr.isSuccess());
System.assert(dr.getErrors().size() > 0);
System.assertEquals('Cannot delete account with related
opportunities.',
dr.getErrors()[0].getMessage());
}
}
// Perform test
Test.startTest();
Database.DeleteResult[] results = Database.delete(accts, false);
Test.stopTest();
// For each record, verify that the deletion was successful
for(Database.DeleteResult dr : results) {
System.assert(dr.isSuccess());
}
}
pg. 59
Developer Console
The Developer Console is an integrated development environment (more typically
called an IDE) where you can create, debug, and test apps in your org.
The Developer Console is connected to one org and is browser-based.
Reference
Developer Console Basics
Workspaces
Workspaces in the Developer Console help you organize information to show just
what you need as you work on each of your development tasks. Although it sounds
like a fancy term, a workspace is simply a collection of resources, represented by tabs,
in the main panel of the Developer Console. You can create a workspace for any
group of resources that you use together.
Workspaces reduce clutter and make it easier to navigate between different
resources.
pg. 60
// Helper method
private static Boolean inspectResults(Messaging.SendEmailResult[] results) {
Boolean sendResult = true;
// sendEmail returns an array of result objects.
// Iterate through the list to inspect results.
// In this class, the methods send only one email,
// so we should have only one result.
for (Messaging.SendEmailResult res : results) {
if (res.isSuccess()) {
System.debug('Email sent successfully');
}
else {
sendResult = false;
System.debug('The following errors occurred: ' + res.getErrors());
}
}
return sendResult;
}
}
Using the Developer Console, you can create a Lightning component bundle. A
component bundle acts like a folder in that it contains components and all
other related resources, such as style sheets, controllers, and design.
pg. 61
To open a visual force page, File | Open | Entity Type > Pages
Generate/Analyze Logs
Logs are one of the best places to identify problems with a system or program. Using
the Developer Console, you can look at various debug logs to understand how your
code works and to identify any performance issues.
Before execution - enable Open Log in the Enter Apex Code window. The log opens
after your code has been executed.
After execution - double-click the log that appears in the Logs tab.
1. Timestamp — The time when the event occurred. The timestamp is always in
the user’s time zone and in HH:mm:ss:SSS format.
2. Event — The event that triggered the debug log entry. For instance, in the
execution log that you generated, the FATAL_ERROR event is logged when the
email address is determined to be invalid.
3. Details — Details about the line of code and the method name where the
code was executed.
Log Inspector
The handy Log Inspector exists to make it easier to view large logs! The Log Inspector
uses log panel views to provide different perspectives of your code. - To open, Debug
| View Log Panels
1. Stack Tree — Displays log entries within the hierarchy of their objects and
their execution using a top-down tree view. For instance, if one class calls a
second class, the second class is shown as the child of the first.
2. Execution Stack — Displays a bottom-up view of the selected item. It displays
the log entry, followed by the operation that called it.
3. Execution Log — Displays every action that occurred during the execution of
your code.
pg. 62
4. Source — Displays the contents of the source file, indicating the line of code
being run when the selected log entry was generated.
5. Source List — Displays the context of the code being executed when the
event was logged. For example, if you select the log entry generated when the
faulty email address value was entered, the Source List shows
execute_anonymous_apex.
6. Variables — Displays the variables and their assigned values that were in
scope when the code that generated the selected log entry was run.
7. Execution Overview — Displays statistics for the code being executed,
including the execution time and heap size.
Perspective Manager
Log Categories
ApexCode, which logs events related to Apex code and includes information about the
start and end of an Apex method.
Database, which includes logs related to database events, including Database
Manipulation Language (DML), SOSL, and SOQL queries.
Log Levels
Log levels control how much detail is logged for each log category.
From the least amount of data logged (level = NONE) to the most (level =
FINEST).
o NONE
o ERROR
o WARN
o INFO
o DEBUG
o FINE
o FINER
o FINEST
pg. 63
To change, Debug | Change Log Levels
You can set checkpoints only when the Apex log level is set to FINEST.
Checkpoint Inspector
Visualforce Basics
Visualforce is a web development framework that enables developers to build
sophisticated, custom user interfaces for mobile and desktop apps that can be hosted
on the Lightning Platform platform. You can use Visualforce to build apps that align
with the styling of Lightning Experience, as well as your own completely custom
interface.
Reference
Visualforce Basics
pg. 64
<apex:page standardController="Contact" >
<apex:form >
</apex:form>
</apex:page>
Visualforce boasts nearly 150 built-in components, and provides a way for
developers to create their own components.
Visualforce markup can be freely mixed with HTML markup, CSS styles, and
JavaScript libraries, giving you considerable flexibility in how you implement
your app’s user interface.
Hello World
<apex:page>
<h1>Hello World</h1>
</apex:page>
pg. 65
sidebar and showHeader options have no effect in lightning
experience
<apex:page sidebar="false" showHeader="false">
<h1>Hello World</h1>
<p>
This is my first Visualforce Page!
</p>
</apex:page>
You cannot use page blocks sections without parent page blocks.
<apex:page>
<h1>Hello World</h1>
The development mode quick fix and footer is a fast way to quickly create a
new page, or make short edits to an existing page. It’s great for quick changes
or when you want to create a short page to test out some new code on a
blank slate, before incorporating it into your app pages.
The Setup editor, available in Setup by entering Visualforce Pages in the Quick
Find box, then selecting Visualforce Pages, is the most basic editor, but it
provides access to page settings that aren’t available in the Developer Console
or development mode footer.
pg. 66
Solution to Visualforce page challenge
<apex:page showHeader="false">
<apex:image id="salesforceLogo"
value="https://developer.salesforce.com/files/salesforce-developer-network-
logo.png" width="220" height="55" alt="Salesforce Logo"/>
</apex:page>
Visualforce Expressions
The resulting value can be a primitive (integer, string, and so on), a Boolean,
an sObject, a controller method such as an action method, and other useful
results.
Global Variables
Use global variables to access and display system values and resources in your
Visualforce markup.
pg. 67
(and any others) using an expression of the following form: {!
$GlobalName.fieldName }.
{! $User.FirstName } {! $User.LastName }
({! $User.Username })
</apex:pageBlockSection>
</apex:pageBlock>
</apex:page>
Formula Expressions
Visualforce lets you use more than just global variables in the expression
language. It also supports formulas that let you manipulate values.
For example, the & character is the formula language operator that
concatenates strings.
Sample snippets
<apex:page>
pg. 68
<p>Is it true? {! CONTAINS('salesforce.com', 'force.com') }</p>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:page>
Conditional Expressions
Sample snippets
<apex:page>
</apex:page>
pg. 69
</p>
<p>
First Name: {! $User.FirstName }
</p>
<p>
Last Name: {! $User.LastName }
</p>
<p>
Alias: {! $User.Alias }
</p>
<p>
Company: {!$User.CompanyName}
</p>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:page>
$A.get("e.force:navigateToURL").setParams(
{"url": "/apex/pageName?&id=<ID of Object e.g. Account>"}).fire();
</apex:pageBlockSection>
</apex:pageBlock>
</apex:page>
pg. 70
Append id in URL as such: https://<salesforce-
instance>/apex/AccountSummary?core.apexpages.request.devconsole=1&id=<id of
an account>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:page>
Output Components
Components that output data from a record and enable you to design a view-
only user interface.
Visualforce includes nearly 150 built-in components that you can use on your
pages. Components are rendered into HTML, CSS, and JavaScript when a page
is requested.
<apex:detail />
</apex:page>
pg. 71
<apex:detail> is a coarse-grained output component that adds many fields, sections,
buttons, and other user interface elements to the page in just one line of markup.
</apex:page>
Replacing <apex:detail> with specific fields wrapped in page block and page block
section.
<apex:page standardController="Account">
<apex:relatedList list="Contacts"/>
<apex:relatedList list="Opportunities" pageSize="5"/>
</apex:page>
Display a Table
<apex:page standardController="Account">
pg. 72
<apex:pageBlockSection>
<apex:outputField value="{! Account.Name }"/>
<apex:outputField value="{! Account.Phone }"/>
<apex:outputField value="{! Account.Industry }"/>
<apex:outputField value="{! Account.AnnualRevenue }"/>
</apex:pageBlockSection>
</apex:pageBlock>
<apex:pageBlock title="Contacts">
<apex:pageBlockTable value="{!Account.contacts}" var="contact">
<apex:column value="{!contact.Name}"/>
<apex:column value="{!contact.Title}"/>
<apex:column value="{!contact.Phone}"/>
</apex:pageBlockTable>
</apex:pageBlock>
<apex:pageBlock title="Opportunities">
<apex:pageBlockTable value="{!Account.opportunities}" var="opportunity">
<apex:column value="{!opportunity.Name}"/>
<apex:column value="{!opportunity.CloseDate}"/>
<apex:column value="{!opportunity.StageName}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>
Replaced <apex:relatedList> with specific fields using page block table and
columns wrapped in page blocks.
Coarse-grained vs Fine-grained
</apex:page>
pg. 73
Create a Basic Form
<apex:page standardController="Account">
<h1>Edit Account</h1>
<apex:form>
</apex:form>
</apex:page>
<apex:page standardController="Account">
<apex:form>
</apex:form>
</apex:page>
pg. 74
Display Form Errors and Messages
<apex:page standardController="Account">
<apex:form>
</apex:form>
</apex:page>
While you can’t save changes to multiple object types in one request with the
standard controller, you can make it easier to navigate to related records by offering
links that perform actions such as edit or delete on those records.
<apex:page standardController="Account">
<apex:form>
pg. 75
</apex:outputLink>
</apex:column>
<apex:column value="{!contact.Name}"/>
<apex:column value="{!contact.Title}"/>
<apex:column value="{!contact.Phone}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:page>
</apex:pageBlock>
pg. 76
</apex:page>
Use {! listViewOptions } to get a list of list view filters available for an object.
Use {! filterId } to set the list view filter to use for a standard list controller’s
results.
Filter:
<apex:selectList value="{! filterId }" size="1">
<apex:selectOptions value="{! listViewOptions }"/>
<apex:actionSupport event="onchange" reRender="contacts_list"/>
</apex:selectList>
<!-- Contacts List -->
<apex:pageBlockTable value="{! contacts }" var="ct">
<apex:column value="{! ct.FirstName }"/>
<apex:column value="{! ct.LastName }"/>
<apex:column value="{! ct.Email }"/>
<apex:column value="{! ct.Account.Name }"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:page>
Use the pagination features of the standard list controller to allow users to look at
long lists of records one “page” at a time.
Filter:
<apex:selectList value="{! filterId }" size="1">
<apex:selectOptions value="{! listViewOptions }"/>
<apex:actionSupport event="onchange" reRender="contacts_list"/>
</apex:selectList>
<!-- Contacts List -->
pg. 77
<apex:pageBlockTable value="{! contacts }" var="ct">
<apex:column value="{! ct.FirstName }"/>
<apex:column value="{! ct.LastName }"/>
<apex:column value="{! ct.Email }"/>
<apex:column value="{! ct.Account.Name }"/>
</apex:pageBlockTable>
</td>
<td align="center">
<!-- Previous page -->
<!-- active -->
<apex:commandLink action="{! Previous }" value="« Previous"
rendered="{! HasPrevious }"/>
<!-- inactive (no earlier pages) -->
<apex:outputText style="color: #ccc;" value="« Previous"
rendered="{! NOT(HasPrevious) }"/>
<!-- Next page -->
<!-- active -->
<apex:commandLink action="{! Next }" value="Next »"
rendered="{! HasNext }"/>
<!-- inactive (no more pages) -->
<apex:outputText style="color: #ccc;" value="Next »"
rendered="{! NOT(HasNext) }"/>
</td>
<td align="right">
<!-- Records per page -->
Records per page:
<apex:selectList value="{! PageSize }" size="1">
<apex:selectOption itemValue="5" itemLabel="5"/>
<apex:selectOption itemValue="20" itemLabel="20"/>
<apex:actionSupport event="onchange"
reRender="contacts_list"/>
</apex:selectList>
</td>
</tr></table>
</apex:pageBlock>
</apex:form>
</apex:page>
In the progress indicator, three properties are used to indicate how many pages there
are: PageNumber, ResultSize, and PageSize.
The page markup is referencing Boolean properties provided by the standard list
controller, HasPrevious and HasNext, which let you know if there are more records in
a given direction or not.
The records per page selection menu uses an <apex:selectList>.
Aside from Previous and Next, there are also First and Last actions for pagination.
pg. 78
Solution to Account Record Detail challenge
<apex:page standardController="Account" recordSetVar="accounts">
<apex:form>
<apex:pageBlock title="Accounts List" id="accounts_list">
Filter:
<apex:selectList value="{! filterId }" size="1">
<apex:selectOptions value="{! listViewOptions }"/>
<apex:actionSupport event="onchange" reRender="accounts_list"/>
</apex:selectList>
<apex:repeat value="{! accounts }" var="a">
<li>
<apex:outputLink value="/{!a.id}">
{! a.name }
</apex:outputLink>
</li>
</apex:repeat>
</apex:pageBlock>
</apex:form>
</apex:page>
Static Resources
Static resources allow you to upload content that you can reference in a
Visualforce page. Resources can be archives (such as .zip and .jar files), images,
stylesheets, JavaScript, and other files.
Static resources are referenced using the $Resource global variable, which can
be used directly by Visualforce, or used as a parameter to functions such
as URLFOR().
pg. 79
<apex:includeScript value="{! $Resource.jQuery }"/>
</apex:page>
Create zipped static resources to group together related files that are usually updated
together.
Setup | Static Resources | New
e.g. Name as jQueryMobile
Cache Control should be Public
Zip file limit is 5MB (i.e. for jQueryMobile, unzip and remove the demos folder then
zip it again)
pg. 80
<h3>Background Images on Buttons</h3>
<button class="ui-btn ui-shadow ui-corner-all
ui-btn-icon-left ui-icon-action">action</button>
<button class="ui-btn ui-shadow ui-corner-all
ui-btn-icon-left ui-icon-star">star</button>
</div>
</apex:page>
Use the $Resource global variable and the URLFOR() function to reference items
within a zipped static resource.
The URLFOR() function can combine a reference to a zipped static resource and a
relative path to an item within it to create a URL that can be used with Visualforce
components that reference static assets. For
example, URLFOR($Resource.jQueryMobile, 'images/icons-png/cloud-
black.png') returns a URL to a specific graphic asset within the zipped static
resource, which can be used by the <apex:image> component. You can construct
similar URLs for JavaScript and stylesheet files for
the <apex:includeScript> and <apex:stylesheet> components.
Custom Controllers
Custom controllers contain custom logic and data manipulation that can be
used by a Visualforce page. For example, a custom controller can retrieve a list
of items to be displayed, make a callout to an external web service, validate
and insert data, and more—and all of these operations will be available to the
Visualforce page that uses it as a controller.
pg. 81
Create a Visualforce Page that Uses a Custom Controller
<apex:page controller="ContactsListController">
<apex:form>
<apex:pageBlock title="Contacts List" id="contacts_list">
Apex Class
Visualforce Page
<apex:page controller="ContactsListController">
<apex:form>
<apex:pageBlock title="Contacts List" id="contacts_list">
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:page>
pg. 82
Add a New Action Method
Create action methods in your custom controller to respond to user input on
the page.
Apex Class
Visualforce Page
<apex:page controller="ContactsListController">
<apex:form>
<apex:pageBlock title="Contacts List" id="contacts_list">
</apex:pageBlockTable>
pg. 83
</apex:pageBlock>
</apex:form>
</apex:page>
<apex:facet> lets us set the contents of the column header to whatever we want.
The link is created using the <apex:commandLink> component, with
the action attribute set to an expression that references the action method in our
controller.
The attribute reRender="contacts_list" will reload the contacts_list page block.
Instead of hard coding the header text for 'First Name' or 'Last Name', use the
following syntax:
This syntax will automatically translate the header text into whichever language the
org is using.
Apex Class
Visualforce Page
<apex:page controller="NewCaseListController">
<apex:repeat value="{! newCases }" var="case">
<li>
<apex:outputLink value="/{! case.id }">
{! case.ID }
</apex:outputLink>
</li>
</apex:repeat>
</apex:page>
pg. 84
Search Solution Basics
Search is the no.1 most used Salesforce feature.
The search index and tokens allow the search engine to apply advanced features like
spell correction, nicknames, lemmatization, and synonym groups.
Lemmatization identifies and returns variants of the search term, such as add, adding,
and added, in search results.)
The search index also provides the opportunity to introduce relevance ranking into
the mix.
In general, you need a custom search solution when your org uses a custom UI
instead of the standard Salesforce UI.
Other APIs
SOQL vs SOSL
Use SOQL when you know in which objects or fields the data resides and you
want to:
i. Retrieve data from a single object or from multiple objects that are related to
one another.
ii. Count the number of records that meet specified criteria.
iii. Sort results as part of the query.
iv. Retrieve data from number, date, or checkbox fields.
Use SOSL when you don’t know in which object or field the data resides and
you want to:
pg. 85
i. Retrieve data for a specific term that you know exists within a field. Because
SOSL can tokenize multiple terms within a field and build a search index from
this, SOSL searches are faster and can return more relevant results.
ii. Retrieve multiple objects and fields efficiently, and the objects might or might
not be related to one another.
iii. Retrieve data for a particular division in an organization using the divisions
feature, and you want to find it in the most efficient way possible.
Query (REST) and query() (SOAP) — Executes a SOQL query against the specified
object and returns data that matches the specified criteria.
Search (REST) and search() (SOAP) — Executes a SOSL text string search against
your org’s data.
REST API Developer Guide
Syntax
Example
Syntax
Example
Example
pg. 86
FIND {pink hi\-top} RETURNING Merchandise c
SOQL?
You use SOQL for single object searches, when you know the fields to be searched,
when the search term is an exact match for the field (no partial or out-of-order
matches), when you need number, date, or checkbox field data, and when you’re
looking for just a few results
Search queries can be expensive. The more data you’re searching through and the
more results you’re returning, the more you can slow down the entire operation.
Basic strategies:
o Limit which data you’re searching through
o Limit which data you’re returning
Example
pg. 87
Set the starting row offset into the results.
FIND {Cloud Kicks} RETURNING Account (Name, Industry ORDER BY Name LIMIT 10 OFFSET
25)
WITH DIVISION
FIND {Cloud Kicks} RETURNING Account (Name, Industry)
WITH DIVISION = 'Global'
WITH NETWORK
FIND {first place} RETURNING User (Id, Name),
FeedItem (id, ParentId WHERE CreatedDate = THIS_YEAR Order by CreatedDate DESC)
WITH NETWORK = '00000000000001'
WITH PRICEBOOK
Find {shoe} RETURNING Product2 WITH PricebookId = '01sxx0000002MffAAE'
/vXX.X/search/suggestTitleMatches?q=search string&language=article
language&publishStatus=article publication status
pg. 88
/vXX.X/search/suggestTitleMatches?q=race+tips&language=en_US&publishStatus=Online
Response JSON
{
"autoSuggestResults" : [ {
"attributes" : {
"type" : "KnowledgeArticleVersion",
"url" :
"/services/data/v30.0/sobjects/KnowledgeArticleVersion/ka0D00000004CcQ"
},
"Id" : "ka0D00000004CcQ",
"UrlName" : "tips-for-your-first-trail-race",
"Title" : "race tips",
"KnowledgeArticleId" : "kA0D00000004Cfz",
"isMasterLanguage" : "1",
} ],
"hasMoreResults" : false
}
Synonyms
A search for one term in a synonym group returns results for all terms in the group.
For example, a search for USB returns results for all terms in the synonym group,
which contains USB, thumb drive, flash stick, and memory stick.
Setup | Quick Find box | Synonyms
The maximum number of characters per term is 100.
Your organization can create a maximum of 2,000 promoted terms.
Order of Execution:
pg. 89