Cookbook
Cookbook
By Second Edition Authors: Stefanie Anderson, Steven Anderson, Mysti Berry, Phil Choi, Leah Cutter, Mark
Leonard, Chris McGuire, and Garen Torikian
Editor: Mysti Berry
With contributions by
additional members of the salesforce.com
Technology and Services organizations
Force Platform Cookbook
© Copyright 2000-2008 salesforce.com, inc. All rights reserved. Salesforce.com and the “no software”
logo are registered trademarks, and AppExchange, “Success On Demand,” and “The Business Web”
are trademarks of salesforce.com, inc. All other trademarks mentioned in this document are the
properties of their respective owners.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any
form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the
prior consent of the publisher.
The authors would like to thank additional contributors Dave Carroll, Simon Fell, Steve Fisher, Chris
Fry, Richard Greenwald, Larry Jovanovic, Andrea Leszek, Markus Spohn, Nick Tran, and Craig
Weissman. Additional thanks to Andrew Albert, Grant Anderson, Gavin Austin, Eric Bezar, Manoj
Cheenath, Bulent Cinarkaya, Bill Eidson, Matthew Friend, Adam Gross, Michelle Jowitt, Paul Kopacki,
Sarah Marovich, Reena Mathew, Taggart Matthiesen, Yudi Nagata, Kavindra Patel, Igor Pesenson,
Vahn Phan, Varadarajan Rajaram, Bhavana Rehani, EJ Rice, Jim Rivera, Emad Salman, Mary Scotton,
Jerry Sherman, Sagar Wanaselja, Jill Wetzler, and Sarah Whitlock for their advice and support. Special
thanks to the editor and lead writer of the First Edition, Caroline Roth.
Table of Contents
Table of Contents
Welcome..........................................................................................1
About This Book..................................................................................................1
Intended Audience....................................................................................2
Conventions..............................................................................................2
The Sample Recruiting App.....................................................................3
Code Samples...........................................................................................4
Additional Resources................................................................................5
Sending Feedback.....................................................................................7
Understanding the Force Platform........................................................................7
Using Force Platform Tools and Technologies......................................................9
Force Platform Point-and-Click Setup Tools............................................9
Visualforce..............................................................................................12
Apex........................................................................................................12
Force Platform Mobile............................................................................13
The Force Platform Web Services API...................................................13
The Force Platform Migration Tool........................................................14
Force Platform IDE................................................................................14
The Metadata API..................................................................................14
i
Table of Contents
ii
Table of Contents
iii
Table of Contents
Glossary.......................................................................................235
Index...............................................................................................................251
iv
Welcome
Congratulations! You are part of a growing movement of innovative application developers who
are curious about the future of computing, and who no longer want to accept the status quo.
Maybe your organization has just purchased Salesforce licenses, or maybe you've been using
Salesforce for a while and want to extend its capabilities. Maybe you've got a brilliant business
idea and are looking for the best and fastest way to start making money, or maybe you're just
curious about this thing called Apex and want to keep your skill set up to date with the latest
technology.
No matter what angle you're coming from, this book will help application developers leverage
the power of salesforce.com's cloud computing platform to build fully-functional, integrated
Web applications that free you and your organization from the drudgery of maintaining your
own software and hardware stacks. Instead, you can spend your time and money on the ideas
and innovations that make your business applications special, whether you're a lone developer
looking for your first round of venture funding or part of a multi-billion-dollar company with
hundreds of thousands of employees.
To get the most out of the recipes in this book, make sure you understand the experience you
should have, and the tools to supplement these recipes:
1
Welcome
Note: This book indicates the recipes for which salesforce.com Training & Certification
has provided example code or other information. To enroll in courses that provide even
more information and practical experience, see www.salesforce.com/training.
Intended Audience
Developers who are already familiar with the native capabilities of the Force Platform can most
easily implement the recipes in this book. Before working with the recipes you find here, you
should be familiar with the concepts, techniques, and best practices described in the following
books:
To get the most out of this book, you should also have experience with at least one of the
following:
Conventions
This book uses typographical conventions:
2
Welcome
Convention Description
SELECT Name FROM Account In an example, Courier font indicates items that you should
type as shown. In a syntax statement, Courier font also
indicates items that you should type as shown, except for
question marks and square brackets.
SELECT fieldname FROM In an example or syntax statement, italics represent
objectname variables. You supply the actual value.
? In a syntax statement, the question mark indicates the
element preceding it is optional. You may omit the element
or include one.
WHERE In a syntax statement, square brackets surround an element
[conditionexpression] that may be repeated up to the limits for that element. You
may omit the element, or include one or more of them.
3
Welcome
Code Samples
An online version of this book is available on the Developer Force website at
wiki.apexdevnet.com/index.php/Force_Platform_Cookbook. This website also
includes links to the code samples found in this book, as well as any errata that are discovered
after publication.
4
Welcome
Additional Resources
A variety of resources are available to supplement this book.
Documentation
Before working with the recipes in this book, you should work through the first two books in
the series: Force Platform Fundamentals: An Introduction to Custom Application Development in
the Cloud, available on the Developer Force website at
http://wiki.apexdevnet.com/index.php/Force_Platform_Fundamentals, and
Force Platform Developer Guide: Advanced Programming Techniques for Cloud Computing, available
on the Developer Force website at
wiki.apexdevnet.com/index.php/Force_Platform_Developer_Guide
• Access the Help & Training window by clicking Help or Help & Training in the
upper-right corner of any Salesforce page. Alternatively, access a context-sensitive view of
the Help & Training window by clicking Help for this Page on the right side of any page
title bar, or the help link on the right side of any related list.
• Review white papers, multimedia presentations, and other documentation in the Native
Framework section of the Developer Force website at
wiki.apexdevnet.com/index.php/Native_Framework.
• Review tips and best practices at www.salesforce.com/community.
Visualforce:
Apex:
• Read the Force Platform Web Services API Developer's Guide, available at
www.salesforce.com/apidoc.
5
Welcome
• Review whitepapers, multimedia presentations, and other documentation in the API section
of the Developer Force website at
wiki.apexdevnet.com/index.php/Web_Services_API.
• Review white papers, multimedia presentations, and other documentation in the API
section of the Developer Force website at
wiki.apexdevnet.com/index.php/Web_Services_API.
Training Courses
Training classes are also available from salesforce.com Training & Certification. You can find
a complete list of courses at www.salesforce.com/training.
• The Force Platform Migration Tool is generally available. To access it, log in to your
Salesforce organization and select Setup ➤ Develop ➤ Tools and click Force Platform
Migration Tool.
• The Force Platform IDE is the world's first integrated development environment for cloud
computing. Based on Eclipse technology, the Force Platform IDE provides professional
developers and development teams the tools to code, test, deploy, and version Force Platform
components, including Apex, Visualforce, custom objects, layouts, and more. For
information about this tool, see
http://wiki.apexdevnet.com/index.php/Force.com_IDE.
• The latest version of AJAX Tools, a Force Platform AppExchange package alternative to
the Force Platform IDE, includes syntax-highlighting, a lightweight version of Force
Platform Explorer, and code samples. To download the latest version, go to
http://www.salesforce.com/appexchange/detail_overview.jsp?NavCode__c=&id=a0330000002foeKAAQ.
• Force Platform Explorer is a lightweight, .NET-based tool that lets you browse the schema
within your organization, edit data values, and build and test SOQL and SOSL queries
While the Force Platform IDE and AJAX Tools include a lightweight version of this handy
application, the stand-alone .NET version of Force Platform Explorer includes more
functionality, including the ability to test SOSL statements, view documents, and update
6
Welcome
Tip: Visit Salesforce.com Ideas at ideas.salesforce.com and see what users are asking
for. Salesforce.com Ideas is a forum where salesforce.com customers can suggest new
product concepts, promote favorite enhancements, interact with product managers and
other customers, and preview what salesforce.com is planning to deliver in future
releases. You can use Salesforce.com Ideas both to find ideas for new applications, and
to post your pet peeves about how the platform works for you.
Sending Feedback
The authors made every effort to ensure the accuracy of the information contained within this
book, but neither they nor salesforce.com assumes any responsibility or liability for any errors
or inaccuracies that may appear. If you do find any errors, please send feedback to
[email protected], or visit the Developer Force discussion boards at
www.salesforce.com/developer/community/index.jsp.
7
Welcome
available to all users with every new release. And you'll have the peace of
mind of knowing that any app you were using or building before the new
release will work just as well after the release too, regardless of whether it
was a standard CRM app from salesforce.com or a custom app you
developed on your own.
As a developer, the platform's multitenant architecture also means that
you never have to worry about scaling your apps from one to one thousand
or even to one million users—all of the infrastructure to handle such
growth is provided free of charge, automatically behind the scenes. That
leaves you more time to focus on your business problems and solutions,
rather than spending time trying to anticipate the pressures that increased
usage might exert on your apps.
Distribution
Any app written on the platform has access to a built-in community of
potential customers on the Force Platform AppExchange at
www.salesforce.com/appexchange/. Unlike traditional software,
where you have to create an install wizard and send your code to a
manufacturer to cut hundreds of CDs, you can easily share and distribute
your app on the AppExchange with only a few clicks of the mouse. You
can quickly share your apps privately with just the people you want, or
you can publish your apps for anyone to download.
If you do publish an app publicly, the community of users on the
AppExchange can take your app for a test drive and review comments
from other users about how well it worked. Additionally, information
about the users who end up downloading your app is sent directly to you
in the form of a new lead in any Salesforce organization that you specify.
When you're ready to release new versions of your app, the AppExchange
also helps you communicate and manage the upgrade process for all of
your users. You can track which of your customers is on which version of
your app, and you never have to worry that your users have broken or
deleted any component your app relies on.
Development
The Force Platform comes with a wide variety of built-in, point-and-click
functionality that can help you build your apps faster. Need a way to store
data in your app? Define new database objects, fields, and relationships
declaratively with the mouse, rather than by composing SQL CREATE
statements. Need to control which users have access to different kinds of
data? Again, no coding necessary—just use the security and sharing
framework to define permissions at different levels of granularity, from
individual fields to entire objects and applications. The Force Platform
includes point-and-click tools for everything from string localization to
8
Welcome
workflow rules and approval processes, from custom reports and dashboards
to page layouts and data import wizards—which means you can spend
less time recreating the "plumbing" that makes your applications run and
more time on the unique functionality that sets your apps apart from your
competitor's.
And what happens when you want to go beyond the capabilities of the
point-and-click tools the platform provides? The Force Platform Web
Services API, Apex, and Visualforce give you the flexibility you need to
build the applications you want. Integrate third-party Web services with
embedded mashups, change the logic behind every function with Apex
classes and triggers, and redesign the user interface the way you want with
Visualforce. You're limited only by your imagination!
The Force Platform includes a number of tools that can help you develop apps. These tools
allow you to define the data, business logic, and user interface for an application. The recipes
in this book focus on these tools.
• Custom objects
Similar to a database table, a Salesforce object is a structure for storing
data about a certain type of entity, such as a person, account, or job
application. Salesforce includes over a dozen standard objects that
support default apps like Sales and Service & Support, but it also allows
you to build custom objects for your own application needs. In
Salesforce, each object automatically includes built-in features like a
9
Welcome
• Custom fields
Similar to a column in a database table, a Salesforce field is a property
of an object, such as the first name of a contact or the status of an
opportunity. Salesforce fields support over a dozen different field types,
such as auto-number, checkbox, date/time, and multi-select picklists.
• Custom relationships
Similar to the way primary and foreign keys work in a relational
database, a Salesforce relationship defines a connection between two
objects in which matching values in a specified field in both objects
are used to link related data.
• Field history
Salesforce field history allows you to track changes to fields on a
particular object just by selecting a checkbox on a custom object and
field definition. Users can then review audit logs for changes to sensitive
records without any additional development work.
• Workflow rules
10
Welcome
• Approval processes
Approvals allow you to set up a chain of users who can approve the
creation of sensitive types of records, such as new contracts or vacation
requests.
• Email
Email functionality in Salesforce allows you to email contacts, leads,
person accounts, and users in your organization directly from account,
contact, lead, opportunity, case, campaign, or custom object pages.
• Tabs
Tabs give users a starting point for viewing, editing, and entering
information for a particular object. When a user clicks a tab at the top
of the page, the corresponding tab home page for that object appears.
• Page layouts
Regardless of whether a particular object has a tab, all objects can be
viewed or edited. Page layouts allow you to organize the fields, custom
links, related lists, and other components that appear on those pages.
• Custom views
Custom views allow users to filter the records they see for a particular
object, based on criteria they specify.
11
Welcome
• Console
Salesforce Console allows you to set up a page that displays multiple
objects at a time, streamlining the user experience. It includes a list
view of several different objects at the top of the page, a detail view in
the main window, customizable sidebar components, and mini-detail
views of related information in a dynamic AJAX-based interface.
With this native functionality, app developers can build extensive, full-featured applications
that handle many business needs. For a more thorough introduction to the native functionality
provided by the platform, read Force Platform Fundamentals: An Introduction to Custom Application
Development in the Cloud, available on the Developer Force website at
wiki.apexdevnet.com/index.php/Force_Platform_Fundamentals.
Visualforce
Visualforce is a tag-based markup language that allows developers to develop their own custom
interfaces using standard Salesforce components. Visualforce pages deliver the ability to create
custom pages for your Force Platform applications. Visualforce pages includes a set of tags to
describe a variety of rich components into your page design. These components bring the full
power of the metadata-drivenForce Platform to your pages, while giving you complete freedom
to design pages to suit your specific user interface requirements. The components can either
be controlled by the same logic that's used in standard Salesforce pages, or developers can
associate their own logic with a controller written in Apex. With this architecture, designers
and developers can easily split up the work that goes with building a new application—designers
can focus on the user interface, while developers can work on the business logic that drives the
app.
Apex
Apex is a strongly-typed, object-oriented programming language for executing flow and
transaction control statements on the Force Platform server in conjunction with database
queries, inserts, updates, and deletes. Using syntax that looks like Java and acts like database
stored procedures, Apex allows you to add business logic to your applications in a more efficient,
integrated way than is possible with the Force Platform API.
You can manage and invoke Apex scripts using the following constructs:
• Classes
12
Welcome
A class is a template or blueprint from which Apex objects are created. Classes consist of
other classes, user-defined methods, variables, exception types, and static initialization
code.
Once successfully saved, class methods or variables can be invoked by other Apex scripts,
or through the Force Platform Web Services API (or AJAX Toolkit) for methods that
have been designated with the webService keyword.
In most cases, Apex classes are modeled on their counterparts in Java and can be quickly
understood by those who are familiar with them.
• Triggers
A trigger is an Apex script that executes before or after specific data manipulation language
(DML) events occur, such as before object records are inserted into the database, or after
records have been deleted. Other than Apex Web service methods, triggers provide the
primary means for instantiating Apex.
• Anonymous blocks
An anonymous block is an Apex script that does not get stored in the metadata, but that can
be compiled and executed through the use of the executeanonymous() API call or the
equivalent in the AJAX toolkit.
Force Platform Mobile works with Apex and Visualforce to extend functionality.
13
Welcome
and fields, and much more. Use the API in any language that supports Web services, or within
an s-control by using the AJAX Toolkit.
You can modify metadata in test organizations on Developer Edition or Sandbox, and then
deploy tested changes to production organizations on Enterprise Edition or Unlimited Editions.
You can also create scripts to populate a new organization with your custom objects, custom
fields, and other components.
14
Chapter 1
Modifying and Extending the Salesforce
Application
In this chapter ...
This chapter contains recipes that help you make basic
• Creating a Mass Delete modifications to the Salesforce application.
Button
• Creating a Mass Update Point-and-Click Setup Tools
Button With the Salesforce user interface, nearly all of the data and
• Creating a Custom Detail functionality you need is just a click away. Still, you might
Page Button find that a few modifications here and there could make
• Using Special Characters you even more efficient. For example, you might have a
in Custom Links need to add a custom button to a list view to give users the
• Creating a Button with ability to update all of the records in the list at one time.
Or perhaps you would like to see data from different types
Apex
of objects calculated and displayed in one spot. And of
• Overriding a Standard course, after you've customized these aspects of your app,
Button you want to give users some custom documentation that
• Creating a Consistent describes how to use it. All of this is possible, and easy to
Look and Feel with Static do, on the Force Platform!
Resources
• Formatting a Currency In this chapter, you'll learn how to create custom buttons,
such as a Mass Delete and a Mass Update button, override
• Building a Table of Data
the action of a standard Salesforce button, pass parameters
in a Visualforce Page
into your custom button or link code, redirect users to a
• Building a Form in a different URL when they go to a standard Salesforce page,
Visualforce Page and provide custom help documentation with your app.
• Creating a Wizard with You'll also learn how to model many-to-many relationships
Visualforce Pages between objects, how to retrieve and display data from
• Creating a Custom related records, and how to block record creation according
Visualforce Component to data on related records. We'll use a combination of native
15
Chapter 1: Modifying and Extending the Salesforce Application
Apex
Apex enables a new class of applications and features to be
developed and deployed on the platform by providing the
ability to capture business logic and rules. The language
uses a combination of Java-like syntax with API functions
and SOQL to let you define triggers, classes, and other
representations of business logic that can interact with the
platform at a low level. Conceptually similar to a stored
procedure system, Apex allows almost any kind of
transactional, complex logic to be developed and run entirely
in the cloud.
16
Creating a Mass Delete Button
Problem
You want to add a button to the top of the Contacts related list in an account detail page that
allows users to select multiple contacts in the list and delete all of them at once.
Solution
Create a new button on Contact, and then add the button to the related list on the Account
page layout.
2. In the Custom Buttons and Links related list, click New. Assign it the following
attributes:
• Label: Mass Delete
• Name: Mass_Delete_Contacts
• Description: Contacts related list button on an account detail page to allow
users to select multiple contacts in the list and delete all of them at once.
17
Chapter 1: Modifying and Extending the Salesforce Application
3. In the code for the button, use the GETRECORDIDS() function to acquire the IDs
of the contacts that the user selects. The code then performs the appropriate logic,
updates the database using the AJAX Toolkit, and refreshes the page as confirmation
to the user.
For example:
} else if (idsToDelete.length == 0) {
alert("Please select the contacts you wish to delete.");
}
18
Creating a Mass Delete Button
c. From the Related Lists Section, double-click the Contacts related list to
edit it.
d. In the Custom Buttons section, select the Mass Delete button in the
Available buttons list and click Add.
e. Click OK to close the popup.
f. Click Save on the page layout. Your changes are not saved until you do so.
7. Optionally, enhance the usability of your app even more by adding the Mass Delete
button to the Contacts Search Results and List View layouts as well:
a. Click Setup ➤ Customize ➤ Contacts ➤ Search Layouts.
Tip: For a new button on a custom object, navigate to Setup ➤
Create ➤ Objects, and click the name of the object.
b. Click Edit next to the search layout you want to customize. You can add
buttons to the Search Results and List View search layouts.
c. In the Custom Buttons section, use the arrows to move the Mass Delete
button to the Selected Buttons list.
d. Click Save on the page layout.
8. Open an account record and scroll to the Contacts related list to view the button.
Discussion
The GETRECORDIDS() function is the crucial call in any mass action list button. It returns an
array of string record IDs for the selected records in the list view or related list. It always takes
a single $ObjectType merge field with the specified type of the records that are included in
the list (for example, $ObjectType.Case or $ObjectType.Position__c).
If you're creating a mass delete button for a list of activities, you must specify whether the
activities are tasks or events. If tasks, use $ObjectType.Task in your call to GETRECORDIDS().
If events, use $ObjectType.Event instead.
Note: The GETRECORDIDS() function is only available in custom buttons and links.
The $ObjectType merge field is only available in Visualforce pages, custom buttons
and links, and validation rules.
Tip: If you'd rather not go to the trouble of creating this button yourself, install it and
others like it for free by going to Force Platform AppExchange and searching for the
Mass Delete app. Installing this package includes a mass delete custom button for each
standard object. The custom list button for activity lists also deletes all selected tasks
or events at once.
19
Chapter 1: Modifying and Extending the Salesforce Application
See Also
• Creating a Mass Update Button on page 20
• "Getting Started with Custom Buttons and Links," a Breeze presentation available at
salesforce.breezecentral.com/buttonsandlinks
• "Embedded Mash-Up Samples," a PDF available at
blogs.salesforce.com/features/files/salesforce_useful_scontrols.pdf
• "Operators and Functions" in the Salesforce online help
• "Understanding Global Variables" in the Salesforce online help
• AJAX Toolkit Developer's Guide
Problem
You want to add a button to the top of a list of records that allows users to select multiple items
in the list and perform the same updates on all of them.
Figure 3: A Mass Close Button for Job Applications on a Positions Detail Page
20
Creating a Mass Update Button
Solution
Create a custom mass action list button on the object that's associated with the records that
appear in the list.
To illustrate this solution, we’ll enhance the sample Recruiting application by giving users a
quick way to close multiple job applications after a position has closed. Instead of forcing users
to open each job application and change its Stage and Status fields, we'll set up a list button
called Reject Applications to do this for us.
To implement this solution on your own, use the same general procedure for creating a list
button as was described in the recipe for Creating a Mass Delete Button on page 17. Instead of
using the JavaScript code for the mass delete button, though, swap in the following code:
// Get the list of job applications that should be closed by using the
// $ObjectType merge field to indicate the type of record Ids that
// are expected.
//
var jobAppIdArr = {!GETRECORDIDS( $ObjectType.Job_Application__c )};
} else {
21
Chapter 1: Modifying and Extending the Salesforce Application
} catch(error) {
alert("Failed to update Job Applications with error: " + error);
See Also
• The Sample Recruiting App on page 3
• Creating a Mass Delete Button on page 17
• "Getting Started with Custom Buttons and Links," a Breeze presentation available at
salesforce.breezecentral.com/buttonsandlinks
• "Embedded Mash-Up Samples," a PDF available at
blogs.salesforce.com/features/files/salesforce_useful_scontrols.pdf
• "Operators and Functions" in the Salesforce online help
• "Understanding Global Variables" in the Salesforce online help
22
Creating a Custom Detail Page Button
Problem
You want to add a custom button to the account detail page.
Solution
First define the button, then add it to the appropriate page layout. For example, the following
procedure creates a simple button that, when clicked, displays a popup dialog with a welcome
message.
1. Define the button:
a. Click Setup ➤ Customize ➤ Accounts ➤ Buttons and Links.
Tip: For a new button on a custom object, navigate to Setup ➤
Develop ➤ Objects, and click the name of the object.
23
Chapter 1: Modifying and Extending the Salesforce Application
Discussion
Custom buttons allow you to build custom actions directly into Salesforce. A button can
navigate to a URL, or execute JavaScript when a user clicks it. It can open a new window,
display in the existing window, or perform an action behind the scenes.
Tip: If you define a button that displays in a new window, you can control the
properties of that window by clicking Window Open Properties in the button's detail
page.
Because buttons are more recognizable and easy to find on a page than custom links, use them
for your most important value-add functionality.
See Also
• Creating a Mass Delete Button on page 17
• Creating a Mass Update Button on page 20
24
Using Special Characters in Custom Links
Problem
You have customers who are using non-English versions of Internet Explorer 6 or another
browser, and URLs in and custom links aren't passing special characters properly. The characters
either don't show up, or the entire line of code is copied.
Solution
Encode the URLs with the encodeURI() JavaScript function. For example:
<script language="JavaScript">
function redirect()
{parent.frames.location.replace(encodeURI("/003/e?retURL=" +
"%2F{!Contact.Id}&con4_lkid={!Account.Id}&" +
"con4{!Account.Name}&00N30000001KqeH=" +
"{!Account.Account_Name_Localized__c}" +
"&cancelURL=%2F{!Account.Id}"))}
redirect();
</script>
Problem
You want to create a new button that executes logic written in Apex.
Solution
Define a webService method in Apex and then call it using the AJAX Toolkit in a button.
For example, suppose you want to create a Mass Add Notes button on accounts:
25
Chapter 1: Modifying and Extending the Salesforce Application
1. Define the Web service method in Apex by clicking Setup ➤ Develop ➤ Apex
Classes, clicking New, and adding the following code into the body of your new
class:
global class MassNoteInsert{
2. Then, click Setup ➤ Customize ➤ Accounts ➤ Buttons and Links, and click New
in the Custom Buttons and Links related list.
3. Name the button and assign it the following attributes:
• Display Type: List Button
• Behavior: Execute JavaScript
• Content Source: OnClick JavaScript
if (idsToInsert.length) {
26
Overriding a Standard Button
5. Click Save.
6. Click Setup ➤ Customize ➤ Accounts ➤ Search Layouts and add the button to
the Accounts List View layout.
To test this new button, visit the Accounts tab and click Go! to view a list of accounts. Select
one or more accounts and click Mass Add Notes.
See Also
• Creating a Mass Delete Button on page 17
• Creating a Mass Update Button on page 20
Problem
You want to override what happens when a user clicks a standard button, such as New or Edit.
Solution
To override a button on a standard object:
1. Click Setup ➤ Customize, select the name of the object, and then click Buttons
and Links.
2. In the Standard Buttons and Links related list, click Override next to the name of
the button you want to change.
3. Select Visualforce Page as the content type.
4. Select a Visualforce page from the content name drop-down list.
Only Visualforce pages that use the standard controller for the object on which the
button appears can be selected. For example, if you want to use a page to override
the Edit button on accounts, the page markup must include the
standardController="Account" attribute on the <apex:page> tag:
<apex:page standardController="Account">
</apex:page>
5. Click Save.
27
Chapter 1: Modifying and Extending the Salesforce Application
2. Scroll down to the Standard Buttons and Links related list and click Override next
to the name of the button you want to override.
3. Select Visualforce Page as the content type.
4. Select a Visualforce page from the content name drop-down list.
Only Visualforce pages that use the standard controller for the object on which the
button appears can be selected. For example, if you want to use a page to override
the Edit button on accounts, the page markup must include the
standardController="Account" attribute on the <apex:page> tag:
<apex:page standardController="Account">
</apex:page>
5. Click Save.
Discussion
For standard and custom objects in the application, you can override the following standard
buttons:
• New
• View
• Edit
• Delete
• Clone
• Accept
Additionally, some standard objects also have special actions. For example, Leads have Convert,
Change Status, Add to Campaign, and others. These actions can also be overridden.
However, because Visualforce pages are only available through the Salesforce user interface,
overriding the New button for contacts has no effect on new contacts that are created via Apex
or the API.
You can only override standard buttons that appear on an object's detail page or list views.
Buttons that only appear on an edit page or in reports can't be overridden.
As a final note, button overrides shouldn't be confused with Apex triggers, which execute in
tandem with the typical behavior. Button overrides replace the standard behavior entirely. For
example, if you override the Delete button on Accounts and a user attempts to delete an
account, it won't necessarily be deleted. Instead, the user is forwarded on to the URL of your
choosing, which may or may not include code to delete the account. If you define an Apex
delete trigger on Accounts, however, the normal delete behavior still occurs, as long as the
trigger doesn't prevent deletion by adding an error to the record.
28
Creating a Consistent Look and Feel with Static Resources
See Also
• Overriding a Standard Page on page 46
• Overriding a Page for Some, but not All, Users on page 53
Problem
You want all of your Visualforce pages to have a consistent look and feel that can easily be
updated.
Solution
Create a static resource from a Cascading Style Sheet and include it in your Visualforce pages.
A static resource; is a file or archive that you upload and then reference in a Visualforce page.
To change the look of your pages, all you need to do is update the static resource with your
new styles, and every page that uses that static resource displays with your new style.
Discussion
Static resources can be used for many other purposes, not just stylesheets. A static resource can
be an archive (such as .zip and .jar files), image, stylesheet, JavaScript, or any other type of file
you want to use in your Visualforce pages.
29
Chapter 1: Modifying and Extending the Salesforce Application
A static resource name can only contain alphanumeric characters, must begin with a letter, and
must be unique in your organization. If you reference a static resource in Visualforce markup
and then change the name of the resource, the Visualforce markup is updated to reflect that
change.
A single static resource can be up to 5 MB in size, and an organization can have up to 250 MB
of static resources, total.
See Also
• Managing Static Resources in the Salesforce online help
• Visualforce Developer's Guide
Formatting a Currency
Problem
You want to display a currency value, but the API doesn't return currencies in a formatted
state.
Solution
Use Visualforce to display currencies in a manner that is correctly formatted for your users.
The following Visualforce page will show Opportunity date and amount values in the format
for their locale.
<apex:page standardController="Opportunity">
<apex:pageBlock title="Opportunity Fields">
<apex:pageBlockSection >
<apex:outputField value="{!opportunity.closedate}"/>
<apex:outputField value="{!opportunity.amount}"/>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:page>
Discussion
The Visualforce <apex:outputfield> component does the formatting automatically for
users in all locales.
30
Building a Table of Data in a Visualforce Page
Problem
You want to display a set of records in a table in a Visualforce page.
Solution
Define a custom controller that returns the set of records you want to display, and then use
the <dataTable> tag to display the results. For example, assume that you want to display the
contacts associated with a record in a table.
2. Iterate over the resulting contacts with the <dataTable> tag. This tag allows us to
define an iteration variable that we can use to access the fields on each contact:
<apex:page controller="mySecondController" tabStyle="Account">
31
Chapter 1: Modifying and Extending the Salesforce Application
Discussion
Notice that the <apex:dataTable> tag supports styling attributes like cellPadding and
border. You can also style individual data elements with HTML tags. For example, the
following <apex:dataTable> component makes the last name of each contact bold:
See Also
• Using Query String Parameters in a Visualforce Page on page 139
• Building a Form in a Visualforce Page on page 33
• Using AJAX in a Visualforce Page on page 141
• Creating a Wizard with Visualforce Pages on page 35
32
Building a Form in a Visualforce Page
Problem
You want to create a Visualforce page that captures input from users.
Solution
Use the <apex:form> tag with one or more input components and a <apex:commandLink>
or <apex:commandButton> tag to submit the form.
Discussion
To gather data for fields that are defined on a custom or standard object, use the
<apex:inputField> tag. This tag renders the appropriate input widget based on the field's
type. For example, if you use an <apex:inputField> tag to display a date field, a calendar
widget displays on the form. If you use an <apex:inputField> tag to display a picklist field,
a drop-down list displays instead.
For example, the following page allows users to edit and save the name of an account.
<apex:page standardController="Account">
<apex:form>
<apex:pageBlock title="Hello {!$User.FirstName}!">
You belong to the {!account.name} account.<p/>
Account Name:
<apex:inputField value="{!account.name}"/>
<p/>
<apex:commandButton action="{!save}"
value="Save New Account Name"/>
</apex:pageBlock>
</apex:form>
</apex:page>
Note: Remember, for this page to display account data, the ID of a valid account
record must be specified as a query parameter in the URL for the page.
Notice that the <apex:commandButton> tag is associated with the save action of the standard
controller, which performs the same action as the Save button on the standard edit page. The
<apex:inputField> tag is bound to the account name field by setting the value attribute
with an expression containing dot notation.
33
Chapter 1: Modifying and Extending the Salesforce Application
The <apex:inputField> tag can be used with either standard or custom controllers and
enforces all security restrictions and other flags on the field, such as whether a value for the
field is required, or whether it must be unique from the value on all other records of that type.
Its only drawback is that if it's used to display variables in a custom controller that aren't bound
to an object field, the variables might not display the way you want them to.
See Also
• Using Query String Parameters in a Visualforce Page on page 139
• Building a Table of Data in a Visualforce Page on page 31
• Using AJAX in a Visualforce Page on page 141
• Creating a Wizard with Visualforce Pages on page 35
34
Creating a Wizard with Visualforce Pages
Problem
You want to create a three-step opportunity wizard that allows users to create an opportunity
at the same time as a related contact, account, and contact role:
• The first step captures information related to the account and contact
• The second step captures information related to the opportunity
• The final step shows which records will be created and allows the user to save or cancel
Solution
Define three Visualforce pages for each of the three steps in the wizard, plus a single custom
controller that sets up navigation between each of the pages and tracks the data that the user
enters.
The code for the three pages and the controller is included here; however, it's important to
understand the best procedure for creating them because each of the three pages references
the controller, and the controller references each of the three pages. In what appears to be a
Catch-22, you can't create the controller without the pages, but the pages have to exist in order
for you to refer to them in the controller.
Luckily, we can work our way out of this conundrum because we can define a page that's
completely empty. To create the wizard pages and controller:
1. Navigate to the URL for the first page:
https://<host>.salesforce.com/apex/opptyStep1
2. Click Create Page newOpptyStep1.
3. Repeat the two steps above for the other pages in the wizard: opptyStep2 and
opptyStep3.
Note: Although you can create an empty page, the reverse is not true. In
order for a page to refer to a controller, the controller has to exist with all of
its methods and properties.
Now all three of the pages exist. Even though they are empty, they need to exist
before we can create a controller that refers to them.
/*
* This class is the controller behind the New Customer Opportunity
35
Chapter 1: Modifying and Extending the Salesforce Application
// The next four methods return one of each of the four class
// variables. If this is the first time the method is called,
// it creates an empty record for the variable.
public Account getAccount() {
if(account == null) account = new Account();
return account;
}
// This method performs the final save for all four objects, and
// then navigates the user to the detail page for the new
// opportunity.
36
Creating a Wizard with Visualforce Pages
return opptyPage;
}
<apex:page controller="newOpportunityController"
tabStyle="Opportunity">
<apex:sectionHeader title="New Customer Opportunity"
subtitle="Step 1 of 3"/>
<apex:form>
<apex:pageBlock title="Customer Information">
<!-- This facet tag defines the "Next" button that appears
in the footer of the pageBlock. It calls the step2()
controller method, which returns a pageReference to
the next step of the wizard. -->
37
Chapter 1: Modifying and Extending the Salesforce Application
<apex:facet name="footer">
<apex:commandButton action="{!step2}" value="Next"
styleClass="btn"/>
</apex:facet>
<apex:pageBlockSection title="Account Information">
<apex:page controller="newOpportunityController"
tabStyle="Opportunity">
<apex:sectionHeader title="New Customer Opportunity"
subtitle="Step 2 of 3"/>
<apex:form>
<apex:pageBlock title="Opportunity Information">
<apex:facet name="footer">
<apex:outputPanel>
<apex:commandButton action="{!step1}" value="Previous"
styleClass="btn"/>
<apex:commandButton action="{!step3}" value="Next"
38
Creating a Wizard with Visualforce Pages
styleClass="btn"/>
</apex:outputPanel>
</apex:facet>
<apex:pageBlockSection title="Opportunity Information">
<apex:panelGrid columns="2">
<apex:outputLabel value="Opportunity Name"
for="opportunityName"/>
<apex:inputField id="opportunityName"
value="{!opportunity.name}"/>
<apex:outputLabel value="Amount"
for="opportunityAmount"/>
<apex:inputField id="opportunityAmount"
value="{!opportunity.amount}"/>
<apex:outputLabel value="Close Date"
for="opportunityCloseDate"/>
<apex:inputField id="opportunityCloseDate"
value="{!opportunity.closeDate}"/>
<apex:outputLabel value="Stage"
for="opportunityStageName"/>
<apex:inputField id="opportunityStageName"
value="{!opportunity.stageName}"/>
<apex:outputLabel value="Role for Contact:
{!contact.firstName}
{!contact.lastName}"
for="contactRole"/>
<apex:inputField id="contactRole"
value="{!role.role}"/>
</apex:panelGrid>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
<apex:page controller="newOpportunityController"
tabStyle="Opportunity">
<apex:sectionHeader title="New Customer Opportunity"
subtitle="Step 3 of 3"/>
<apex:form>
<apex:pageBlock title="Confirmation">
<apex:facet name="footer">
<apex:outputPanel>
<apex:commandButton action="{!step2}" value="Previous"
styleClass="btn"/>
<apex:commandButton action="{!save}" value="Save"
styleClass="btn"/>
</apex:outputPanel>
</apex:facet>
<apex:pageBlockSection title="Account Information">
<apex:panelGrid columns="2">
39
Chapter 1: Modifying and Extending the Salesforce Application
You'll now have a wizard that is composed of the following three pages:
40
Creating a Wizard with Visualforce Pages
Discussion
On page 1 of the wizard, data about the associated contact and account is gathered from the
user. Notice the following about the code for the first page of the wizard:
• Some tags, including <apex:pageBlock>, can take an optional <apex:facet> child
element that controls the header or footer of the component. The order in which the facet
tag appears in the <apex:pageBlock> body doesn't matter because it includes a name
41
Chapter 1: Modifying and Extending the Salesforce Application
attribute that identifies where the element should be placed. In this page of the wizard, the
facet tag defines the Next button that appears in the footer of the pageBlock area.
• An <apex:commandButton> tag represents a user control that executes a method in the
controller class. In this page of the wizard, the Next button calls the step2() method in
the controller, which returns a PageReference to the next step of the wizard. Command
buttons must appear in a form, because the form component itself is responsible for
refreshing the page display based on the new pageReference.
<apex:facet name="footer">
<apex:commandButton action="{!step2}" value="Next"
styleClass="btn"/>
</apex:facet>
• An <apex:panelGrid> tag organizes a set of data for display. Similar to a table, it simply
takes a number of columns and then places all child elements in successive cells, in
left-to-right, top-to-bottom order. For example, in the Account Information area of this
page, the "Account Name" label is in the first cell, the input field for Account Name is in
the second cell, the "Account Site" label is in the third cell, and the input field for Account
Site is in the fourth.
<apex:panelGrid columns="2">
<apex:outputLabel value="Account Name" for="accountName"/>
<apex:inputField id="accountName" value="{!account.name}"/>
<apex:outputLabel value="Account Site" for="accountSite"/>
<apex:inputField id="accountSite" value="{!account.site}"/>
</apex:panelGrid>
• The value attribute on the first <apex:inputField> tag in the preceding code excerpt
assigns the user's input to the name field of the account record that's returned by the
getAccount() method in the controller.
• The <apex:outputLabel> and <apex:inputField> tags can be bound together when
the id attribute value on <apex:inputField> tag matches the for attribute value on
<apex:outputLabel>. Binding these tags together improves the user experience because
it provides special behavior in the Web page. For example, clicking on the label puts the
cursor in the associated input field. Likewise, if the input is a checkbox, it toggles the
checkmark.
On page 2 of the wizard, data about the opportunity is gathered from the user. Notice the
following about the code for the second page of the wizard:
• Because this page displays two buttons in the pageBlock footer, they're wrapped in an
<apex:outputPanel> tag. This tag needs to be used because <apex:facet> expects
only one child component.
Note: You also must use an <apex:panelGroup> tag within an
<apex:panelGrid> if you want to place more than one component into a single
cell of the grid.
42
Creating a Custom Visualforce Component
• Although the code for placing the Close Date, Stage, and Role for Contact fields
on the form is the same as the other fields, the <apex:inputField> tag examines the
data type of each field to determine how to display it. For example, clicking in the Close
Date text box brings up a calendar from which users can select the date.
On page 3 of the wizard, the user can choose to save the changes or cancel. Notice that the
third page of the wizard simply writes text to the page with <apex:outputText> tags.
See Also
• Using Query String Parameters in a Visualforce Page on page 139
• Building a Table of Data in a Visualforce Page on page 31
• Building a Form in a Visualforce Page on page 33
• Using AJAX in a Visualforce Page on page 141
Problem
You want to use the same functionality on multiple Visualforce pages, but there isn't a standard
component to do it.
Solution
You can create a custom component and use that on your Visualforce page. The following
custom component allows your users to easily increase or decrease a value on the page. First,
create the component, and then add it to a Visualforce page.
<apex:component>
43
Chapter 1: Modifying and Extending the Salesforce Application
description="Maximum value"
type="Integer" required="true"/>
<apex:attribute name="min"
description="Minimum value"
type="Integer" required="true"/>
function decrement(valueId) {
if(document.getElementById(valueId).value >{!min})
{
document.getElementById(valueId).value--;
}
else
{
alert("You can't decrease the number below " + {!min});
}
}
</script>
7. Click Save.
44
Creating a Custom Visualforce Component
<apex:page>
<apex:pageBlock title="Increase or Decrease the Number Displayed">
<apex:form>
<c:addSubValue myvalue="10" min="0" max="15"/>
</apex:form>
</apex:pageBlock>
</apex:page>
6. Click Save.
When you open the page in a browser, you will be see something like the following:
Click the up or down arrow to increase or decrease the number displayed. If you try to change
it to a value lower than 0 or greater than 15, an error message displays in a popup dialog.
Discussion
This solution illustrates how you can mix Visualforce, HTML, and JavaScript within a custom
component. This combination allows you to create very powerful custom components. To
really make this component useful, you can bind the value to a field (like the number of
employees on an account) and update that field when your user submits the form.
The name of a custom component can only contain alphanumeric characters, start with a letter,
and must be unique from all other components in your organization.
45
Chapter 1: Modifying and Extending the Salesforce Application
The description of a custom component appears in the component reference with other standard
component descriptions. If your custom component includes apex:attribute components,
the description will be included in the component reference as well.
When working on a custom component, you can click Quick Save to save your changes and
continue editing your component.
The Visualforce markup must be valid before you can save your component.
Problem
You want to override what happens when a user clicks a tab in Salesforce, such as the Account
or Contact tab.
Solution
To override a standard object tab:
1. Create a Visualforce page called accountOverride.
a. Click SetupDevelop ➤ Pages.
b. Click New.
c. In the label field, enter Override the Account Home Page.
d. In the name field, enter accountOverride.
e. In the description, enter This page will display for all users.
f. In the editor, enter the following markup:
tabStyle="Account">
<apex:form>
<apex:pageBlock>
<apex:pageBlockTable value="{!accounts}" var="a">
<apex:column value="{!a.name}"/>
<apex:column value="{!a.lastmodifieddate}"/>
<apex:column value="{!a.owner.alias}"/>
</apex:pageBlockTable>
</apex:pageBlock>
<apex:panelGrid columns="2">
<apex:commandLink action="{!previous}">
Previous
</apex:commandlink>
<apex:commandLink action="{!next}">
46
Overriding a Standard Page
Next
</apex:commandlink>
</apex:panelGrid>
</apex:form>
</apex:page>
a. Click Save.
2. Set the page level security to allow all users to view the page.
a. Click Security for the page you just created.
b. Select all the profiles in the Available Profiles list and click Add to add
them to the Enabled Profiles list.
c. Click Save.
Discussion
Overriding a tab overrides what a user sees when he or she clicks on the tab. Overriding a
standard button overrides its functionality in all parts of the Salesforce user interface. For
example, if you override a New button for contacts, it overrides the New button on the Contacts
tab, the New button on any Contacts related list, and the Contact option in the Create New
drop-down list in the sidebar.
You can override the home tab for all standard and custom objects.
See Also
• Overriding a Standard Button on page 27
• Dynamically Updating a Page on page 48
47
Chapter 1: Modifying and Extending the Salesforce Application
Problem
You have fields on a page in your Salesforce application that you only want displayed when
the user has made a specific selection. In this example, you want to capture specific information
about a lost opportunity. During the normal progression of a deal, there is no reason to display
a field called Reason Lost. You want this field to display only when the Stage moves to
Closed Lost. In addition to the Reason Lost field, you would like a required lookup field
that contains competitors names, so that the user can specify which competitor won the deal.
Solution
Using Visualforce, you can create a page that updates just a portion of that page based on a
changed value.
Because you're merely extending the existing behavior of the Force Platform, you don't need
to create a controller (an Apex class).
Some Visualforce components are AJAX aware and allow you to add AJAX behaviors to a
page without having to write any JavaScript. One of the most widely used AJAX behaviors is
a partial page update, in which only a specific portion of a page is updated following some user
action, rather than a reload of the entire page. The simplest way to implement a partial page
update is to use the reRender attribute on a Visualforce component.
This example creates two new fields for Opportunity: Primary Competitor and Reason
Lost. After you create the fields, you need to create a Visualforce page that uses these fields
with an existing opportunity.
48
Dynamically Updating a Page
11. Use the default value for the related list label, and accept the defaults for all the page
layouts where the related list appears.
12. Click Save and New so you can immediately create the second field.
13. Select Text Area (Long) and click Next.
14. In the Field Label text box, enter Reason Lost.
15. In the Field Name text box, enter Reason_Lost.
16. Add a brief description in the Description text box, and what should display as help
text in the Help Text text box as a best practice.
17. Click Next.
18. Use the default values and click Next for field-level security, adding the reference to
page layouts, and adding custom related lists.
19. Click Save.
49
Chapter 1: Modifying and Extending the Salesforce Application
</apex:pageBlockSectionItem>
<apex:inputField value="{!opportunity.amount}"/>
<apex:inputField value="{!opportunity.closedate}"/>
</apex:pageBlockSection>
</apex:actionRegion>
<apex:pageBlockSection title="Closed Lost Information"
columns="1"
rendered="{!opportunity.stageName == 'Closed Lost'}">
<apex:inputField
value="{!opportunity.Primary_Competitor__c}"
required="true"/>
<apex:inputField value="{!opportunity.Reason_Lost__c}"/>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
7. Click Save.
50
Dynamically Updating a Page
Discussion
Note that the Basic Information portion of the page (the top page block) is contained in an
<apex:actionRegion> tag:
<apex:actionRegion >
<apex:inputField value="{!opportunity.name}"/>
. . .
<apex:inputField value="{!opportunity.stageName}">
. . .
<apex:inputField value="{!opportunity.amount}"/>
. . .
<apex:inputField value="{!opportunity.closedate}"/>
. . .
</apex:actionRegion>
51
Chapter 1: Modifying and Extending the Salesforce Application
clicks Save: all the data is still in memory. This is important when you have field dependencies.
For example, once the user specifies Closed Lost, the Primary Competitor field becomes
required. If the updated field information was sent back to the server before the user could
update the field, you would receive an error about the required field.
When a user changes the value of Stage to Closed Lost, a message displays stating "applying
value. . ." This message is generated by the following markup in the Visualforce page.
<apex:inputField value="{!opportunity.stageName}">
<apex:actionSupport event="onchange"
rerender="thePageBlock"
status="status"/>
</apex:inputField>
The input field is opportunity.stageName, the event is onchange, and the status is status.
This is bound to the <apex:actionStatus> tag by the ID status.
In addition to controlling the message that displays, this input field also controls the rendering
of the page. If the field changes, this field specifies that a component named thePageBlock
should be rerendered. The entire page is contained in an <apex:pageBlock> tag with the
ID thePageBlock:
<apex:pageBlock title="Edit Opportunity" id="thePageBlock" mode="edit">
See Also
• Using AJAX in a Visualforce Page on page 141
• Overriding a Page for Some, but not All, Users on page 53
52
Overriding a Page for Some, but not All, Users
Problem
Some of your users should use a custom Visualforce page, while others should use a standard
Salesforce page.
Solution
To override the Account tab with a Visualforce page for most of your users, but send users
with the "System Administrator" profile to the standard Salesforce Account home page:
1. Create a Visualforce page called conditionalAccountOverride.
a. Click Setup ➤ Develop ➤ Pages.
b. Click New.
c. In the label field, enter Override the Account Page for Most
Users.
d. In the name field, enter accountOverride.
e. In the description, enter This page will display for all users,
except System Administrators, when they click the Account
tab.
f. In the editor, enter the following markup:
<apex:page action=
"{!if($Profile.Name !='System Administrator',
null,
urlFor($Action.Account.Tab, $ObjectType.Account,
null, true))}"
standardController="Account"
recordSetVar="accounts"
tabStyle="Account">
g. Click Save.
2. Set the page level security to allow all users to view the page.
a. Click Security for the page you just created.
b. Select all the profiles that will be using this page in the Available Profiles
list and click Add to add them to the Enabled Profiles list.
"Overriding a Page for Some, but not All, Users" contributed by Jill Wetzler, Member of Technical
Staff, for salesforce.com
53
Chapter 1: Modifying and Extending the Salesforce Application
c. Click Save.
Discussion
This solution uses the action attribute on the apex:page component to test the user's profile.
Using the action attribute is a good way to ensure an action is taken when the page loads.
If instead of limiting the standard page to a particular group of users, you want to limit the
override to a particular group of users, such as all "Marketing Users" and "Solution Managers,"
you need to create a controller extension.
To override the Account tab with a custom Visualforce page only for users with the "Marketing
User" or the "Solution Manager" profile:
1. Create a Visualforce page called standardAcctPage.
a. Click Setup ➤ Develop ➤ Pages.
b. Click New.
c. In the label field, enter Override the Account Page for Most
Users.
d. In the name field, enter standardAcctPage.
e. In the description, enter This page will display for all users,
except Marketing Users and Solution Managers, when they
click the Account tab.
f. In the editor, enter the following markup:
<apex:page standardController="account"
extensions="overrideCon"
action="{!redirect}">
<apex:detail/>
</apex:page>
This page overrides your current Account home page. It uses a controller extension
to test the user profile. If the user is a "Marketing User" or "Solution Manager," they
are redirected to a different page.
54
Overriding a Page for Some, but not All, Users
<apex:page standardController="account">
<h1>Override Account page for two profiles</h1>
<apex:detail />
</apex:page>
This is the page that only the "Marketing Users" and "Solutions Managers" will see.
They only get to this page through redirection.
public overrideCon(ApexPages.StandardController
controller) {recordId = controller.getId();}
}
}
}
d. Click Save.
5. Create an override that directs users to the standardAcctPage page when they
click on the Accounts tab.
55
Chapter 1: Modifying and Extending the Salesforce Application
When a user clicks on the Account tab, if their profile is "Marketing User" or "Solution
Manager" the controller extension will automatically redirect them to the customAcctPage.
See Also
• For more information about page level security and creating home page overrides, see the
Salesforce online help.
• For more information about creating page overrides, see Overriding a Standard Button on
page 27.
• For more information about creating controller extensions, see Custom Controllers and
Controller Extensions in the Visualforce Developer Guide.
Problem
In Salesforce, all the information for an account displays on a single page. If there's a lot of
information, you might end up doing a lot of scrolling. You'd like a different way to display
the information for accounts.
Solution
Using a Visualforce page, you can make each section for an account display in a tab, such as
contacts, opportunities, and so on.
To create a tabbed view for account, first you have to create a Visualforce page. Then you have
to override the standard account view to use the page.
"Creating Tabbed Accounts" contributed by Matthew Friend, Senior Technical Sales Engineer, for
salesforce.com
56
Creating Tabbed Accounts
id="tabOpenAct">
<apex:relatedList subject="{!account}"
list="OpenActivities" />
</apex:tab>
<apex:tab label="Notes and Attachments"
name="NotesAndAttachments"
id="tabNoteAtt">
<apex:relatedList subject="{!account}"
list="NotesAndAttachments" />
</apex:tab>
</apex:tabPanel>
</apex:page>
7. Click Save.
57
Chapter 1: Modifying and Extending the Salesforce Application
Discussion
To see your changes, select the Account tab, then select an account to view. Across the top of
the page you should see a list of tabs: Details, Contacts, Opportunities, Open Activities and
Notes and Attachments.
See Also
• Overriding a Standard Page on page 46
• Overriding a Standard Button on page 27
• Adding CSS to Visualforce Pages on page 58
Problem
You want to set your pages apart by changing color, font, or other display options on the page.
Solution
Add CSS markup to your page, then have the appropriate component refer to it.
58
Adding CSS to Visualforce Pages
The following Visualforce page markup is from Creating Tabbed Accounts on page 56. It creates
tabs to display account information.
<apex:page standardController="Account" showHeader="true"
tabStyle="account" >
<apex:tabPanel switchType="client" selectedTab="tabdetails"
id="AccountTabPanel">
<apex:tab label="Details" name="AccDetails" id="tabdetails">
<apex:detail relatedList="false" title="true"/>
</apex:tab>
<apex:tab label="Contacts" name="Contacts" id="tabContact">
<apex:relatedList subject="{!account}" list="contacts" />
</apex:tab>
<apex:tab label="Opportunities" name="Opportunities"
id="tabOpp">
<apex:relatedList subject="{!account}"
list="opportunities" />
</apex:tab>
<apex:tab label="Open Activities" name="OpenActivities"
id="tabOpenAct">
<apex:relatedList subject="{!account}"
list="OpenActivities" />
</apex:tab>
<apex:tab label="Notes and Attachments"
name="NotesAndAttachments" id="tabNoteAtt">
<apex:relatedList subject="{!account}"
list="NotesAndAttachments" />
</apex:tab>
</apex:tabPanel>
</apex:page>
One thing you may notice about this page is that all of the tabs display in the same color. When
you select a tab, it does not change color. Adding the following CSS markup to the Visualforce
page causes the color of the active tab to change when the user selects it.
59
Chapter 1: Modifying and Extending the Salesforce Application
5. Click Save.
The tabbed display with colored tabs looks like the following:
60
Editing Multiple Records Using a Visualforce List Controller
See Also
• Creating Tabbed Accounts on page 56
• Overriding a Standard Page on page 46
Problem
You need to edit a set of records at the same time. A standard detail page, though, only allows
you to edit one record at a time.
Solution
Create a Visualforce page using a standard list controller. The standard list controller enables
you to create Visualforce pages that can display or act on a set of records.
To create a Visualforce page using a standard list controller to edit a list of opportunities:
61
Chapter 1: Modifying and Extending the Salesforce Application
<apex:page standardController="Opportunity"
recordSetVar="opportunities"
tabStyle="Opportunity" sidebar="false">
<apex:form >
<apex:pageBlock >
<apex:pageMessages />
<apex:pageBlockButtons >
<apex:commandButton value="Save"
action="{!save}"/>
</apex:pageBlockButtons>
<apex:pageBlockTable value="{!opportunities}"
var="opp">
<apex:column value="{!opp.name}"/>
<apex:column headerValue="Stage">
<apex:inputField value="{!opp.stageName}"/>
</apex:column>
<apex:column headerValue="Close Date">
<apex:inputField value="{!opp.closeDate}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:page>
7. Click Save.
Substitute salesforce_instance for the instance of Salesforce that you use, such as
na3.salesforce.com. For example,
https://na3.salesforce.com/apex/multOppEdit.
62
Editing Multiple Records Using a Visualforce List Controller
Discussion
Using a standard list controller is very similar to using a standard controller. First you set the
standardController attribute on the <apex:page> component. This specifies the type
of records that you want to access. Then set the recordSetVar attribute on the same
component. This indicates that you're using a standard set controller.
<apex:page standardController="Opportunity"
recordSetVar="opportunities"
tabStyle="Opportunity"
sidebar="false">
The recordSetVar attribute not only indicates that the page uses a list controller, it indicates
the variable name of the record collection. This variable is then used to access data in the record
collection.
In this example, two fields, Stage and Close Date are displayed for edit in the table. They
each form a column in the table:
See Also
• Building a Table of Data in a Visualforce Page on page 31
63
Chapter 1: Modifying and Extending the Salesforce Application
Problem
You want to use a branded top-level domain name for your public Force Platform site—without
exposing the force.com domain in the URL.
Solution
With Force Platform Sites, you can register a branded top-level domain name for your public
site. When users visit your site, they see only the URL that you registered, and not the Force
Platform domain. For example, if you registered http://www.mycompany.com with a domain
name registrar, all site traffic is redirected from that domain to your Force Platform domain.
Users see only http://www.mycompany.com in the browser's address bar.
Note: Branded, top-level domains are not supported for Developer Edition and
Developer Sandboxes. SSL is supported, but if org-wide security settings are enabled,
and the site-level override is not enabled, branded domains revert to
prefix.secure.force.com on customer login.
c. Click Check Availability to confirm that the domain name you entered is
unique. If it is not unique, you are prompted to change it.
d. Read and accept the Force Platform Sites Terms and Use by selecting the
checkbox.
64
Registering a Custom Domain for Your Force Platform Site
e. Click Register My Force.com Domain. After you accept the Terms and
Use and register your Force Platform domain, the change is tracked in your
organization's setup audit trail.
This domain is used for all of your sites, even if you use a branded domain.
2. Register your branded, top-level domain name with a domain name registrar, such
as GoDaddy.com. For this example, let's say you registered www.acme.com. Once
you register the domain, you can also register subdomain names, such as
support.acme.com, partners.acme.com, developers.acme.com.
3. Create CNAME records with your registrar to point your top-level domain and your
subdomains to your Force Platform domain. In this example, create CNAME records
to point from:
• acme.com to acme.force.com
• support.acme.com to acme.force.com
• partners.acme.com to acme.force.com
• acmeideas.com to acme.force.com
Discussion
By registering a top-level domain through a domain name registrar and associating it with
your site, you can create a completely branded experience for your users. With Force Platform
sites and Visualforce pages, you can customize the look and feel, the branding, and public
security settings for each of your sites.
See Also
Customizing the Look and Feel of Your Force Platform Site on page 68
65
Chapter 1: Modifying and Extending the Salesforce Application
Problem
You want to create one Visualforce "About Us" page to be used for several public sites, so you
can't hard-code site-specific values like site URL, site email address, and site template. You
want the "About Us" page to conditionally display links for registration and login, and connect
the "Contact Us" link to each respective site's designated email address.
Solution
Take advantage of the available merge fields when creating the Visualforce pages used for your
public sites. By using merge fields, the same Visualforce page can be used for multiple sites.
Note: To enable Force Platform Sites, contact your salesforce.com representative. The
Force Platform Sites feature is available as Developer Preview in Developer Edition.
See Force Platform Sites Considerations for more information.
Expression Description
{!$Site.Name} Returns the API name of the current site
{!$Site.Domain} Returns the Force Platform domain name for your organization
{!$Site.CustomWebAddress} Returns the value of the Custom Web Address field for the
current site
{!$Site.OriginalUrl} Returns the current domain name displayed in the browser's
address bar
{!$Site.CurrentSiteUrl} Returns the value of the site URL for the current request
{!$Site.LoginEnabled} Returns TRUE if the current site is associated with an active
login-enabled Customer Portal; otherwise returns FALSE
{!$Site.RegistrationEnabled} Returns TRUE if the current site is associated with an active
self-regitration-enabled Customer Portal; otherwise returns
FALSE
{!$Site.IsPasswordExpired} Returns TRUE if the currently logged-in user's password is
expired
{!$Site.AdminEmailAddress} Returns the value of the Site Contact field for the current
site
{!$Site.Prefix} Returns the path of the Default Web Address for the
current site
66
Using Force Platform Site-Specific Merge Fields
Expression Description
{!$Site.Template} Returns the value of the Site Template field for the current
site
{!$Site.ErrorMessage} Returns error IDs or handled error messages thrown by the
application
{!$Site.ErrorDescription} Returns the Apex exception error description
67
Chapter 1: Modifying and Extending the Salesforce Application
Discussion
Force Platform Sites takes advantage of the power and flexibility of Visualforce. With the
out-of-box merge fields and additional expressions available, you can more easily create
feature-rich site pages across multiple sites.
Problem
Your Force Platform site is up and running, but the pages don't have your company's look and
feel. The public sees the standard Salesforce beige and blue. You want to use your company's
logo and stylesheet.
Solution
The default sample pages are all branded with the Force Platform look and feel, but you can
upload your own logo and stylesheet as static resources and reference them from the site
template. The site template controls the layout and branding for your entire site.
Note: To enable Force Platform Sites, contact your salesforce.com representative. The
Force Platform Sites feature is available as Developer Preview in Developer Edition.
See Force Platform Sites Considerations for more information.
68
Customizing the Look and Feel of Your Force Platform Site
3. Now modify the SiteHeader to display your company's logo (Logo) and use your
company's stylesheet:
a. Click Setup ➤ Develop ➤ Components.
b. Click Edit next to the SiteHeader component.
c. Replace the following line:
<apex:image url="{!$Site.Prefix}
{!$Label.site.img_path}/force_logo.gif"
style="align: left;" alt="Salesforce"
width="233" height="55" title="Salesforce"/>
<apex:stylesheet value="{!$Resource.SiteCSS}"/>
e. Click Save.
4. Browse to your site's URL to see your company logo and style.
Discussion
Enable and customize the Visualforce site template and its components to control the design
of your sites. Because the site template can reference other components and static resources,
you can change the look and feel of your site with just a few modifications.
See Also
Registering a Custom Domain for Your Force Platform Site on page 64
69
Chapter 1: Modifying and Extending the Salesforce Application
Problem
You want to be able to track page views and see usage and visitor analysis for your public Force
Platform site so that you can improve its usability and targeted content.
Solution
Force Platform Sites allows you to leverage other Internet services via mash-ups or direct
integration. Google Analytics offers a free analytics service with dozens of reports to help you
track, among other things, your site's visitors and the performance of your marketing campaigns.
Note: To enable Force Platform Sites, contact your salesforce.com representative. The
Force Platform Sites feature is available as Developer Preview in Developer Edition.
See Force Platform Sites Considerations for more information.
2. Copy the JavaScript Tracking Code you receive from Google Analytics.
3. Keeping the Google Analytics window open, open another browser window and do
the following:
a. Click Setup ➤ Develop ➤ Sites.
b. Click the site label link for your site. This takes you to the Site Details
page.
c. On the Site Pages related list, click the SiteTemplate link.
d. Click Edit.
e. Paste the JavaScript Tracking Code, as directed, into the Visualforce page
for your site template.
70
Adding a Feed to Your Force Platform Site
Discussion
The more you understand the usage and traffic patterns for your public site, the more you can
fine-tune the site to improve both the quality of the content and the user experience. Take
advantage of Force Platform Sites Visualforce technology, which allows you to integrate with
powerful Internet applications and services, such as Google Analytics.
Problem
Your Force Platform site is up and running, and you'd like to add a feed that shows your users
up to the last 20 accounts added to your Salesforce organization.
Solution
Define a feed and add it to a Visualforce page in your site. Users can then click an icon to
subscribe to the feed.
Note: To enable Force Platform Sites, contact your salesforce.com representative. The
Force Platform Sites feature is available as Developer Preview in Developer Edition.
See Force Platform Sites Considerations for more information.
Before you start, make sure that sites are enabled and that you have set up a site as described
in the Salesforce online help, including setting the public access settings and enabling feeds
for your site.
1. Click Setup ➤ Develop ➤ Sites to display the list of sites created for your
organization.
2. Click the name of the site where you want to add a feed. Click the Site Label
link, not the Site URL link.
3. In the Syndication Feeds detail area, click New and enter the following values:
• Name: LatestAccounts
• Description: Up to the last 20 accounts added to our
organization.
• Query: SELECT Name from Account
• Mapping ft: "test", fa:"Mysti", et:"Account", ec:Name
• Max Cache Age Seconds: 600
4. Click Save, then click Back to Site Detail to return to the sites detail page.
71
Chapter 1: Modifying and Extending the Salesforce Application
5. Click Preview next to LatestAccounts to test the feed to ensure it delivers the
information you expect. The preview page displays what the feed will display to
users, and provides a link to the site where the feed will be displayed.
6. After the feed is created and tested, add a link to the feed in your Visualforce page
by adding the following markup:
<A HREF="/xml/services/LatestAccounts">Latest Accounts</A>
The path assumes your page is located in the base directory of the site. You may
have to adjust the path if it is not.
7. Now users who visit the page can click the link Latest Accounts and subscribe to
the feed.
Discussion
The feed created here is very simple. You can write much more complex SOQL queries for
the feed to tailor the information for your users. For example, the following query would report
up the last five accounts created later than yesterday:
The SOQL query defines what information is collected, but the mapping determines what
information is displayed in the feed itself, using elements of the ATOM protocol. For an
explanation of the elements, see "Defining Syndication Feeds" in the Salesforce online help.
This topic also explains some of the limitations placed on SOQL for feeds queries. These
limits are in place to ensure good performance.
It's important that you set public access settings for objects properly. Because the feed issues
queries as the site guest user, you must assign the correct public access settings to the profile
for that guest user, or queries may return either not enough information or information about
objects that you don't wish to share with the guest user.Similarly, you must set sharing rules
appropriately. Instructions for setting the public access settings and sharing rules are provided
in the Salesforce online help.
Feeds support the use of bind variables in both the query definition and mapping. At run time,
the value of the bind variable is passed in the URL. More information about bind variables is
provided in the Salesforce online help.
See Also
• Visualforce Developer's Guide
• Customizing the Look and Feel of Your Force Platform Site on page 68
• Registering a Custom Domain for Your Force Platform Site on page 64
• Using Force Platform Site-Specific Merge Fields on page 66
• Integrating Your Force Platform Site on page 70
72
Using Dynamic Apex
Problem
You want to write Apex scripts that use standard sObjects, then you want to package your code
so other organizations can download it from Force Platform AppExchange. In addition, you
want your code to work regardless of the standard objects available on the organization that
downloads your package.
Solution
Dynamic Apex enables developers to create more flexible applications by providing them with
the ability to do the following:
• Access information about sObjects in general and the fields of an sObject.
Describe information for an sObject includes whether that type of sObject supports operations
like create or undelete, the sObject's name and label, the sObject's fields and child objects,
and so on. The describe information for a field includes whether the field has a default
value, whether it is a calculated field, the type of the field, and so on.
• Write SOQL queries, SOSL queries, and DML that are dynamic; that is, you don't have
to know all the names, objects, or parameters when you first write the code.
Dynamic SOQL and SOSL queries provide the ability to execute SOQL or SOSL as a string
at runtime, while dynamic DML provides the ability to create a record dynamically and
then insert it into the database using DML. Using dynamic SOQL, SOSL, and DML, an
application can be tailored precisely to the organization, as well as the user's permissions.
This can be useful for applications that are installed from Force Platform AppExchange.
Note: Because this recipe uses the development mode of Visualforce, be sure you have
enabled it. To enable Visualforce development mode, click Setup ➤ My personal
Information ➤ Personal Information, and click Edit. Select the Development
Mode checkbox, and then click Save.
This recipe demonstrates using describe information for an organization. It uses a Visualforce
page for displaying the information.
1. Create the Apex class that the Visualforce page uses to populate a dropdown with a
list of all the sObjects available in the organization. Click Setup ➤ Develop ➤ Apex
Classes, then click New.
73
Chapter 1: Modifying and Extending the Salesforce Application
2. Copy and paste the following into the Body text field for the class:
public class Describer {
schemaMap.get(selectedObject).getDescribe().fields.getMap();
3. To create the Visualforce page, enter the following URL in your browser's address
bar:
74
Using Dynamic Apex
4. http://MySalesforceInstance/apex/DescribePage
<apex:form id="Describe">
<apex:commandButton
value="Get Describe Object Fields"
action="{!showFields}"/>
</apex:pageblockbuttons>
<apex:pageblocksection >
<apex:selectOptions value="{!objectNames}"/>
</apex:selectList>
</apex:pageblocksection>
<apex:pageblocksection
id="fieldList" rendered=
"{!not(isnull(selectedObject))}">
<apex:panelBarItem label="{!fls.key}"/>
</apex:panelBar>
</apex:pageblocksection>
</apex:pageBlock>
</apex:form>
</apex:page>
75
Chapter 1: Modifying and Extending the Salesforce Application
Discussion
The controller first populates the dropdown with the list of sObjects. When a user clicks the
Get Describe Object Fields button on the Visualforce page, the controller populates the
<apex:panelbar> on the Visualforce page with the names of all the fields associated with
that sObject.
See Also
Using Properties in Apex on page 143
76
Chapter 2
Managing Workflow and Approvals
In this chapter ...
Your organization operates more efficiently with
• Managing Large standardized internal procedures and automated business
Opportunities Using processes. Use workflow rules and approval processes to
Time-Based Workflow automate them. Not only do you save time, but you enforce
consistency across your business practices.
• Managing Lost
Opportunities Using Build workflow rules to trigger actions, such as email alerts,
Workflow tasks, field updates, and outbound messages based on time
• Using Workflow to Notify triggers, criteria, or formulas. Use approval processes to
Case Contact for Priority automate all of your organization's approvals, from simple
Cases to complex.
• Using Workflow to Add
Account Names to
Opportunity Names
• Requiring Parallel
Approvals for Large
Campaigns
• Using a Matrix-Based
Dynamic Approval Process
• Sending Outbound
Messages with Workflow
• Tracking Outbound
Messages from Workflow
77
Chapter 2: Managing Workflow and Approvals
Problem
You want to create a workflow rule to send an email alert when an opportunity with an amount
greater than $1,000,000 is created, as well as 30 days before, 15 days before, and 5 days after
the opportunity close date. After the close date, you want to assign a task to the opportunity
owner to update the deal.
Solution
Create a workflow rule with multiple time triggers to send email alerts based on the criteria
you specify. In this example, the rule criteria are that the opportunity must have a value greater
than $1,000,000 and must not be closed. First we'll create the workflow rule, then define the
immediate and time-dependent workflow actions.
2. Add an immediate workflow action to send an email alert when an opportunity meets
the above criteria.
a. Click Add Workflow Action and select New Email.
b. Define the workflow alert by providing the description, selecting the email
template, and adding the recipients. In this example, the recipient might
be the VP of Sales role. To find the right VP, select Role in the Search
menu and click Find.
c. Click Save.
3. Create time triggers for large opportunities nearing their close dates, as well as one
for missed opportunities.
a. Click Add Time Trigger in the Time-Dependent Workflow Actions
section of the Edit Workflow Rule page.
78
Managing Large Opportunities Using Time-Based Workflow
b. Set a time trigger for 30 days before Opportunity: Close Date and
click Save.
c. Set a time trigger for 15 days before Opportunity: Close Date and
click Save.
d. Set a time trigger for 5 days after Opportunity: Close Date and click
Save.
d. Click Save.
5. Return to the Workflow Rule detail page and click Activate to activate the rule.
Discussion
You want to be able to track large opportunities closely. Proactively manage your opportunities
using workflow rules with multiple time triggers. As the close date approaches for a large deal,
automatic workflow actions, like email alerts, increase the visibility to executives who can then
take the necessary actions to close the deal. Time-dependent actions can also be used to remind
management to review lost deals after the close date to determine the causes of failure, and to
learn what to do next time to ensure success.
See Also
Managing Lost Opportunities Using Workflow on page 80
79
Chapter 2: Managing Workflow and Approvals
Problem
You want to create a workflow rule to send an email alert when an opportunity with an amount
greater than $1,000,000 is closed and lost.
Solution
Create a workflow rule to send email alerts based on the formula you specify. In this example,
the rule criteria are that the opportunity must have a value greater than $1,000,000 and Stage
changes from Proposal/Price Quote to Closed Lost. First we'll create the workflow rule, then
define the immediate workflow actions.
g. Click Check Syntax to ensure there were no mistakes, then click Save &
Next.
2. Add an immediate workflow action to send an email alert when an opportunity meets
the above criteria.
a. Click Add Workflow Action and select New Email.
b. Define the workflow alert by providing the description, selecting the email
template, and adding the recipients. In this example, the recipient might
be the VP of Sales role. To find the right VP, select Role in the Search
menu and click Find.
c. Click Save.
3. Return to the Workflow Rule detail page and click Activate to activate the rule.
80
Using Workflow to Notify Case Contact for Priority Cases
Discussion
If you lose a large opportunity, you want to know why. Using a workflow rule with a formula
for the rule criteria, you can track specific field value changes using sophisticated formula
functions, such as ISPICKVAL and PRIORVALUE. When a large opportunity is lost, automatic
workflow actions, like email alerts, notify key people in your organization so that they can
investigate what went wrong, and learn what to do next time to ensure success.
See Also
Managing Large Opportunities Using Time-Based Workflow on page 78
Problem
You want to create a workflow rule to send an email alert to the case contact when you receive
a high priority case for accounts that have a Platinum service-level agreement (SLA).
Solution
Create a workflow rule to send email alerts based on the criteria you specify. In this example,
the rule criteria are that the case priority is high and the account SLA is platinum. First we'll
create the workflow rule, then define the immediate workflow actions.
2. Add an immediate workflow action to send an email alert to the case contact when
a case meets the above criteria.
a. Click Add Workflow Action and select New Email.
b. Define the workflow alert by providing the description, selecting the email
template, and adding the recipients. In this example, the recipient is the
case contact.
81
Chapter 2: Managing Workflow and Approvals
c. Click Save.
3. Return to the Workflow Rule detail page and click Activate to activate the rule.
Discussion
When a high priority account files a case, you want to know right away. Use a workflow rule
with an automatic email alert to notify the right people so that they can take care of your highest
priority customers. Workflow email alerts can be used to notify anyone inside or outside of
your organization—they don't have to be Salesforce users.
Problem
You want to create a workflow rule to enforce a consistent naming standard for opportunities.
The opportunity name for any opportunity that does not include the associated account name
changes to Account Name: Opportunity Name.
Solution
Create a workflow rule to evaluate all opportunity names based on the formula you specify. If
the name does not include the associated account name, it will be added. First we'll create the
workflow rule, then define the immediate actions.
g. Click Check Syntax to ensure there were no mistakes, then click Save &
Next.
2. Add an immediate workflow action to update the Opportunity Name field when
an opportunity meets the above criteria.
82
Requiring Parallel Approvals for Large Campaigns
d. Click Save.
3. Return to the Workflow Rule detail page and click Activate to activate the rule.
Discussion
You want to be able to enforce consistency across your business practices. Using a workflow
rule with a formula for the rule criteria, you can set standard naming conventions for
opportunities or other objects. Formulas can span multiple objects and, when used with field
updates within a workflow rule, can be a powerful tool for enforcing company standards.
Problem
You want to create an approval process to route all approval requests to the Director of
Marketing, route all approved requests $25,000 or greater to two designated Vice Presidents
(VPs) for unanimous approval, and finally, send all requests, regardless of size, to the Director
of Finance for final approval. Requests under $25,000 that are approved by the Director of
Marketing should skip the two VPs and go directly to the Director of Finance.
Solution
Create a three-step approval process based on the criteria you specify. In this example, all
requests are sent to the Director of Marketing, approved requests under $25,000 skip the VPs
approval step and go directly to the Director of Finance; and approved requests $25,000 or
greater are sent to the VPs for parallel approval. Both must approve the request.
First we'll create the approval process, then define the approval steps and final approval/rejection
actions.
83
Chapter 2: Managing Workflow and Approvals
l. Click Save.
m. Select Yes, I'd like to create an approval step now, then
click Go.
84
Requiring Parallel Approvals for Large Campaigns
f. Select the No, I'll do this later... option and click Go.
85
Chapter 2: Managing Workflow and Approvals
8. Return to the Approval Process detail page and click Activate to activate the approval
process.
Discussion
Automating your company's campaign budget approval process enforces your best business
practices. Use a single approval process to manage multiple conditions and approval
requirements. Requiring multiple, unanimous approvals enforces stricter standards for large
budget approvals, while the option to skip certain approval steps streamlines the process. Using
86
Using a Matrix-Based Dynamic Approval Process
parallel approvals and the "else" option, you can create sophisticated processes to match your
complex business needs.
Problem
You want to be able to create a single criteria-based approval process to route opportunity
discount approval requests to designated approvers, based on the requester's region and the
opportunity's account type.
Solution
The Dynamic Approval Routing application, available for free on Force Platform AppExchange,
provides a sample solution that automates an opportunity discount approval process based on
region and account type, and routes opportunities through three required levels of approval.
The Dynamic Approval Routing application comes packaged with the necessary custom object,
validation rule, Apex class, and Apex triggers and tests. The package also comes with
documentation on how to customize the application to fit your needs.
2. Once installation is complete, click All Tabs, then click Customize My Tabs. Add
the Approval Routing Rules tab to the Selected Tabs list.
3. Customize the following fields' picklist values to match your organization.
• Owner Region—Custom picklist field on the User object to model the
opportunity owner’s region. Set the region for all opportunity owners.
• Account Type—Custom picklist field on the Opportunity object to model the
account type associated with the opportunity. Set the account type for all
opportunities.
Note: You may have to enable the Owner Region and Account Type
fields in the Page Layouts for Users and Opportunities, respectively.
87
Chapter 2: Managing Workflow and Approvals
4. Create an Approval Routing Rule for each combination of region and account type.
a. Select the Account Type and Owner Region for the rule. The Routing
Key, a composite key based on the Account Type and Owner Region
fields, is created automatically.
b. For each rule, select approvers for Level1, Level2, and Level3, the
custom user lookup fields used to model the levels of authorization.
Approvers for all opportunities are assigned according to the submitter's
region and the opportunity's type.
6. Create the three approval steps to correspond to the Level1, Level2, and Level3
approver fields defined in the Approval Routing Rule.
88
Sending Outbound Messages with Workflow
a. From the Approval Process Detail page, click New Approval Step.
b. Name the steps Level 1 Approval, Level 2 Approval, Level 3
Approval.
c. For the step criteria, select All records should enter this step.
d. Select Automatically assign to approver(s) and choose Related
User.
e. Find and select Level1, Level2, and Level3 for your three steps, respectively.
f. Click Save.
Once you become more familiar with how these routing rules work, you can design data-driven
approval routing for all approval processes involving multiple routing criteria.
Discussion
In previous Salesforce releases, implementing a solution for an organization with multiple
account types and regions would require multiple approval processes: one for each combination
of region and account type. As the numbers of account types and regions grow, the number
of approval processes required jump significantly. For example, if you had two account types
and three regions, you would need six approval processes; if you had 10 account types and five
regions, you would need to create and maintain 50 approval processes.
By leveraging the Dynamic Approval Routing application, which uses a custom object, validation
rules, and Apex code, you can create a single data-driven approval process to handle your most
complex approval processes.
Problem
You want to send an outbound message to an external Web service when records are created
or updated in Salesforce.
Solution
Set up a workflow rule to send the outbound message, generate the WSDL document for the
message, and then set up a listener in your language of choice.
"Sending Outbound Messages with Workflow" contributed by Markus Spohn, Director of Product
Management, Integration, for salesforce.com
89
Chapter 2: Managing Workflow and Approvals
For the following example, we'll revisit our sample Recruiting application. We'll set up a
message to a legal services provider if a visa is required before a candidate can start his or her
new job:
1. Set up a workflow rule that triggers an outbound message.
a. Click Setup ➤ Create ➤ Workflow & Approvals ➤ Workflow Rules
and create a new workflow rule that fires when a candidate is created, or
when a candidate is edited and did not previously meet the rule's criteria.
Set the criteria for the rule to be "Visa Required equals True."
b. Add an outbound message workflow action:
a. In the Immediate Workflow Actions area, click Add Workflow
Action ➤ New Outbound Message.
b. Enter a name and description for the outbound message.
c. Specify the Endpoint URL for the recipient of the message.
Salesforce sends a SOAP message to this endpoint, which is the
Web service listener that will consume the outbound message.
d. Select a Salesforce user whose security settings will control the
data that's visible for the message.
e. Select Include Session ID if you want the Salesforce
sessionId included in the message. You should include it if
you intend to make API calls and you don't want to include a
username and password in the body of your message (which is
far less secure than sending the sessionId).
f. Select the field values that you want included in the outbound
message.
g. Click Save.
c. Activate the workflow rule by returning to the Workflow Rule detail page
and clicking Activate.
2. Generate the WSDL document for your outbound message: Return to the Outbound
Message detail page by clicking Setup ➤ Create ➤ Workflow & Approvals ➤
Outbound Messagaes and selecting the name of the outbound message. Then click
Click for WSDL. This file is bound to the outbound message and contains the
instructions about how to reach the endpoint service and what data is sent to it. Save
the file to your local machine.
3. Build a listener for the outbound message. This Web service endpoint has to conform
to the definition of the WSDL file. For example, to build a listener using .NET:
a. Run wsdl.exe/serverInterfaceleads.wsdl with .NET 2.0. This
generates NotificationServiceInterfaces.cs, which defines the
notification interface.
b. Create a class that implements NotificationServiceInterfaces.cs.
90
Sending Outbound Messages with Workflow
While there are a number of ways to do this, one simple way is to compile
the interface to a .dll first (.dlls must be in the bin directory in ASP.NET):
mkdir bin csc /t:library /out:bin\nsi.dll
NotificationServiceInterfaces.cs
<%@WebService class="MyNotificationListener"
language="C#"%>
class MyNotificationListener : INotificationBinding
{
public notificationsResponse
notifications(notifications n)
{
notificationsResponse r =
new notificationsResponse();
r.Ack = true;
return r;
}
}
c. Deploy the service by creating a new virtual directory in IIS for the directory
that contains MyNotificationListener.asmx.
You can test that the service is deployed by viewing the service page with
a browser. For example, if you create a virtual directory named
salesforce, navigate to
http://localhost/salesforce/MyNotificationListener.asmx.
Discussion
Although this recipe only outlines the procedure for a .NET-based solution using IIS, the
process for other Web services-enabled languages and tools is similar. Note that your listener
must meet the following requirements:
• It must be reachable from the public Internet.
• If it uses SSL, it must use one of the following ports:
◊ 80: this port only accepts HTTP connections
◊ 443: this port only accepts HTTPS connections
◊ 7000-10000: these ports accept HTTP or HTTPS connections
• If it requires client certificates, you must have the current Salesforce client certificate available
at Setup ➤ Develop ➤ API.
91
Chapter 2: Managing Workflow and Approvals
• The common name (CN) of the listener's certificate must match the domain name for your
endpoint's server, and the certificate must be issued by a Certificate Authority trusted by
the Java 2 Platform, Standard Edition 5.0 ( JDK 1.5).
See Also
• Tracking Outbound Messages from Workflow on page 92
• Sending Messages from Apex
• "Outbound Messaging" in the Force Platform Web Services API Developer's Guide at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#
sforce_api_om_outboundmessaging.htm
• The "Creating an Outbound Messaging Notification Service with CSharp and .Net
Framework 2.0" whitepaper at wiki.apexdevnet.com/index.php/
Creating_an_Outbound_Messaging_Notification_Service_with_CSharp_and_.Net_Framework_2.0
Problem
You want to track the status of the outbound messages that have been sent to external servers
as a result of a workflow rule.
Solution
Click Setup ➤ Monitoring ➤ Outbound Messages.
Alternatively, click Setup ➤ Create ➤ Workflow & Approvals ➤ Outbound Messages, and
then click View Message Delivery Status. From this page you can:
• View the status of your outbound messages, including the total number of attempted
deliveries
• View the action that triggered the outbound message by clicking any workflow or approval
process action ID
• Click Retry next to a message to immediately re-deliver the message
• Click Del next to a message to permanently remove the outbound message from the queue
See Also
• Sending Outbound Messages with Workflow on page 89
"Tracking Outbound Messages from Workflow" contributed by Markus Spohn, Director of Product
Management, Integration, for salesforce.com
92
Tracking Outbound Messages from Workflow
• "Outbound Messaging" in the Force Platform Web Services API Developer's Guide at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#
sforce_api_om_outboundmessaging.htm
• The "Creating an Outbound Messaging Notification Service with CSharp and .Net
Framework 2.0" whitepaper at wiki.apexdevnet.com/index.php/
Creating_an_Outbound_Messaging_Notification_Service_with_CSharp_and_.Net_Framework_2.0
93
Chapter 3
Searching and Querying Data
In this chapter ...
Truly useful, cloud computing business apps include business
• Using the Force Platform logic and processes that help companies run their businesses
Explorer to Examine Your efficiently. As we've mentioned, the Force Platform gives
Data Model you the power to write code and develop components to
incorporate business logic, such as data validation, into your
• Using SoqlXplorer to
app. Pretty much any business process you write for your
Examine Your Data app will require your code to search, query, and examine
Model sets of records upon which the business process will operate.
• Choosing Between SOQL So what's the best way to do that?
and SOSL
• Constructing SOQL and In this chapter, you'll learn how to examine your app's
SOSL Queries in the objects, relationships, and fields in a graphical way. You'll
Force Platform Explorer also learn the difference between SOQL and SOSL and
how to use them to construct queries that examine sets of
• Querying Multiple Related
records in your app. Then you'll see how to use SOQL to
Objects Using
query related objects using their relationship associations
Relationship Queries and how to filter your queries by a relative date or the
• Finding a Contact, Lead, division of a record. Finally, you'll use the AJAX toolkit to
or Person Account query your data in a command-line environment. These
• Retrieving Data Based on examples and best practices are a great way to get started
a Relative Date developing your own queries to manipulate the data in ways
• Finding Search Data that are unique to your app.
Based on Division
You can use the recipes in this chapter without setting up
• Previewing Query Results the Force Platform API, because the tools you'll use are
• Sorting Query Results already set up for you. But all the query techniques you learn
• Viewing Tags here can be used if you do work with the API. For more
• View Records with Tags information, see Chapter 6: Integrating Applications with the
• Writing Shorter Queries API and Apex on page 195.
Using Outer Joins
95
Chapter 3: Searching and Querying Data
Problem
You want to browse through the fields, attributes, and relationships of every object in your
Salesforce organization, and you're on a Windows platform.
Solution
Use the Force Platform Explorer, an open-source C#.Net client application available on
Developer Force. Force Platform Explorer is a lightweight, .NET-based tool that lets you
browse the schema within your organization, edit data values, and build and test SOQL and
SOSL queries While the Force Platform IDE and AJAX Tools include a lightweight version
of this handy application, the stand-alone .NET version of Force Platform Explorer includes
more functionality, including the ability to test SOSL statements, view documents, and update
database values. To download it, go to
wiki.apexdevnet.com/index.php/Apex_Explorer.
After installing the Force Platform Explorer, open the application and log in by clicking the
Login button and entering your standard Salesforce username and password. At this point the
Force Platform Explorer issues a describeGlobal() call to the API to populate the interactive
list of objects in the right sidebar.
Tip: The permissions associated with your login affect the visibility of objects and
fields in the Force Platform Explorer. Be sure that your login has access to the data
you need to explore—a user with the "Modify All Data" permission typically works
best.
96
Using the Force Platform Explorer to Examine Your Data Model
Once you've logged in, you can expand any object to explore its fields, attributes, and
relationships. For example, the following information is available if you expand the Account
object:
Id Prefix
The first three characters of the Salesforce ID for records of this object
type. For example, the ID of any account record always starts with 001.
Likewise, contact records always start with 003.
Labels
The labels that are used to display this object in both singular and plural
form.
Frontdoor URLs
The URLs that can be used to reach detail, edit, and list pages for the
object in a Web browser. See Creating a Custom Detail Page Button on
page 23.
Attributes
A list of actions that you can perform on the object. See
www.salesforce.com/us/developer/docs/api/index_CSH.htm#
sforce_api_calls_describesobjects_describesobjectresult.htm .
Child Relationships
The relationships that have been defined on other objects that reference
this object as the "one" side of a one-to-many relationship. For example,
97
Chapter 3: Searching and Querying Data
if you expand the Child Relationships node under the Account object,
contacts, opportunities, and tasks are included in this list.
Note: Relationships that are defined on this object so that it
represents the "many" side of a one-to-many relationship (for
example, the Parent Account relationship on the Account object)
are included in the list of fields.
Fields
The fields that are available on this object. These, too, have associated
attributes, relationships, a label, and a field type that you can expand for
more information. For example, if you expand the Account object's
CreatedById field:
Note: Standard objects are listed by their standard names, even if you've renamed
them.
Discussion
If you want to connect to a different instance of Salesforce, such as your Developer Sandbox
or a pre-release instance, click Tools ➤ Options, and set the domain name of the Endpoint
to the appropriate server. For example, if you wanted to point to a sandbox organization,
change:
https://www.salesforce.com/services/Soap/u/14.0
To:
https://test.salesforce.com/services/Soap/u/14.0
98
Using SoqlXplorer to Examine Your Data Model
You can also use the Endpoint parameter to change to a different version of the API. For
example, to have the Force Platform Explorer use Version 14 of the API, change your Endpoint
to:
https://www.salesforce.com/services/Soap/u/14.0
See Also
• Constructing SOQL and SOSL Queries in the Force Platform Explorer on page 102
• Using SoqlXplorer to Examine Your Data Model on page 99
Problem
You want to browse through the fields, attributes, and relationships of every object in your
Salesforce organization, and you're on the Mac OS X platform.
Solution
For Mac users, SoqlXplorer is a great counterpart to the Force Platform Explorer for Windows.
SoqlXplorer provides metadata exploration, a SOQL query tester, and a graphical schema view
for examining object relationships (a piece of functionality that's only available on the Mac
OS X platform!). Download SoqlXplorer from Simon Fell's PocketSOAP website at
www.pocketsoap.com/osx/soqlx. After the download automatically extracts itself, drag
the SoqlXplorer icon to your Applications folder to complete the installation.
After installing SoqlXplorer, open the application and log in by entering your standard Salesforce
username and password and specifying the server to which you want to connect. Choose
www.salesforce.com to connect to the normal production servers, or test.salesforce.com to
connect to a sandbox organization.
After you click Login, SoqlXplorer issues a describeGlobal() call to the API to populate
the interactive list of objects in the right sidebar.
You can expand any object to explore its fields and relationships. To view attributes for an
object, toggle the Details button to On in the bottom right corner of the window. If you select
an object field, the Details popup shows properties for the field instead.
99
Chapter 3: Searching and Querying Data
Two views are available in the main window: SOQL and Schema.
• Use SOQL view to open a SOQL query editor where you can construct and execute SOQL
queries. The queries you write use syntax-highlighting to improve legibility, and you can
double-click an object's name to automatically build a query that selects all available fields.
You can also double-click any result data to copy and paste it elsewhere.
• Use Schema view to open an interactive entity relationship diagram (ERD) of the objects
in your organization. Select any object in the right sidebar to view that object's parent
relationships (in blue) and child relationships (in orange). You can expand the fields of any
object by clicking the + toggle button in the upper right corner of any object, and you can
double-click an object to move it to the center of the view.
100
Choosing Between SOQL and SOSL
See Also
• Constructing SOQL and SOSL Queries in the Force Platform Explorer on page 102
• Using the Force Platform Explorer to Examine Your Data Model on page 96
Problem
You know that the platform supports Salesforce Object Query Language (SOQL) and Salesforce
Object Search Language (SOSL), but you don't know what the difference is between the two,
or when to use one over the other.
101
Chapter 3: Searching and Querying Data
Solution
A SOQL query is the equivalent of a SELECT clause in a SQL statement. Use SOQL with
a query() call when:
• You know in which objects or fields the data resides
• You want to retrieve data from a single object or from multiple objects that are related to
one another
• You want to count the number of records that meet particular criteria
• You want to sort your results as part of the query
• You want to retrieve data from number, date, or checkbox fields
A SOSL query is a programmatic way of performing a text-based search. Use SOSL with a
search() call when:
• You don't know in which object or field the data resides and you want to find it in the most
efficient way possible
• You want to retrieve multiple objects and fields efficiently, and the objects may or may not
be related to one another
• You want to retrieve data for a particular division in an organization with Divisions, and
you want to find it in the most efficient way possible
Tip: Although SOQL was previously the only one of the two query languages that
allowed condition-based filtering with WHERE clauses, as of the Summer '07 release
SOSL supports this functionality as well.
See Also
• Constructing SOQL and SOSL Queries in the Force Platform Explorer on page 102
• Finding Search Data Based on Division on page 110
• "Salesforce Object Query Language (SOQL)" at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_soql.htm
• "Salesforce Object Search Language (SOSL)" at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_sosl.htm
Problem
You want to construct a SOQL or SOSL query, but you don't want to type all the object and
field names by hand.
102
Constructing SOQL and SOSL Queries in the Force Platform Explorer
Solution
Use the Force Platform Explorer to build and test SOQL and SOSL queries with
point-and-click functionality. Building SOQL and SOSL queries in the Force Platform
Explorer saves you time if you're learning SOQL and SOSL syntax, or if you're looking for
an easy way to test queries before implementing them in an s-control or integration.
Note: This recipe describes how to create SOQL and SOSL queries in the Force
Platform Explorer, but other metadata explorer tools such as SoqlXplorer for Mac OS
X, or the SOQL Explorer in the Force Platform IDE work in a similar manner.
After logging in to the Force Platform Explorer, the Describe Results pane displays an
interactive list of selectable fields for each object in your Salesforce organization. Selecting one
or more fields from this pane automatically creates a SOQL query in the SOQL Tester pane
on the left.
For example, the following screenshot shows a SOQL query that was automatically generated
after selecting the MailingCity and MailingState fields of the Contact object.
• If you want to include a field from a related object in a query, expand the Child
Relationships element under the parent object, expand the child object you want to
query, and then expand its Child Fields. You can add a child field to your query just
by selecting its checkbox.
103
Chapter 3: Searching and Querying Data
• If you want to filter the results by any additional values, enter the WHERE clause for the
SOQL query by hand.
Once the query is constructed, click Query to execute it against the database. Results appear
in the lower pane.
If you want to save the query for future use, click Save and enter a label. Saved queries are
stored in SOQL Samples ➤ Saved Queries.
The Force Platform Explorer also allows you to construct SOSL queries in the same way:
1. In the SOSL Tester tab enter a Search Query according to the same rules that
you use for entering queries in the search text box in the Salesforce user interface.
For example, acme*, or jerry g.
2. In the Search Group drop-down list, specify whether you want to search all possible
fields or restrict your search to just name, email, or phone fields.
3. Optionally, specify the objects and fields that you want returned by your SOSL query
in the Return Field Spec text area. For example:
Lead(Name, Phone ORDER BY Name DESC), Contact(Name, Phone WHERE
createddate = THIS_FISCAL_QUARTER)
104
Querying Multiple Related Objects Using Relationship Queries
See Also
• Choosing Between SOQL and SOSL on page 101
• "Salesforce Object Query Language (SOQL)" at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_soql.htm
• "Salesforce Object Search Language (SOSL)" at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_sosl.htm
Problem
You want to use as few SOQL queries as possible to access data from multiple related objects.
Solution
Use SOQL relationship syntax to pull data from related records in a single query.
For each of the following examples, the child object is the object on which the relationship
field (the foreign key) is defined, and the parent is the object that the child references:
Basic Child-to-Parent (Foreign Key) Traversal
To traverse a relationship from a child to a parent, use standard dot
notation off the name of the relationship. For example, this SOQL query
retrieves information about contacts from the Contact object, along with
the name of each contact's related account (the parent object):
SELECT Id, LastName, FirstName, Account.Name
FROM Contact
105
Chapter 3: Searching and Querying Data
Using the nested query, we're specifying that for each opportunity we want
the respective set of OpportunityLineItem records that are related through
the OpportunityLineItems child relationship.
Combined Child-to-Parent and Parent-to-Child Traversal
Foreign key and aggregate traversals can also be combined in a single
query. For example:
SELECT Id, Name, Account.Name,
(SELECT Quantity, UnitPrice, TotalPrice,
PricebookEntry.Name,
PricebookEntry.Product2.Family
FROM OpportunityLineItems)
FROM Opportunity
See Also
• Constructing SOQL and SOSL Queries in the Force Platform Explorer on page 102
• "Relationship Queries" at www.salesforce.com/us/developer/docs/api/
index_CSH.htm#sforce_api_calls_soql_relationships.htm
• "Salesforce Object Query Language (SOQL)" at www.salesforce.com/us/developer/
docs/api/index_CSH.htm#sforce_api_calls_soql.htm
Problem
You want to write a query to find a person, but you don't know whether this person is stored
as a lead, as a contact, or as a person account.
Solution
Perform the search with one SOSL query, rather than multiple SOQL queries. For example:
106
Finding a Contact, Lead, or Person Account
• To look for Joe in all searchable text fields in the system, and return the IDs of the records
where Joe is found in a case-insensitive search:
FIND {Joe}
• To look for all email fields that start with jo or end in acme.com, and return the IDs of the
records where those fields are found:
FIND {"jo*" OR "*acme.com"}
IN EMAIL FIELDS
Tip: If you know you're looking for a name, an email address, or a phone number,
it's more efficient to narrow your search scope to only name fields, email fields, or
phone fields, respectively, rather than searching every field.
• To look for the name Joe Smith or Joe Smythe in the name field on a lead or contact only,
and return the name and phone number of any matching record that was also created in
the current fiscal quarter:
FIND {"Joe Smith" OR "Joe Smythe"}
IN NAME FIELDS
RETURNING
lead(name, phone WHERE createddate = THIS_FISCAL_QUARTER),
contact(name, phone WHERE createddate = THIS_FISCAL_QUARTER)
If you want to search for records based on a query string that was entered by a user, first escape
any special characters that were entered by the user, and then construct the appropriate SOSL
string. For example, the following JavaScriptl searches leads, contacts, and accounts for any
instance of a record named "Phil Degauss":
<html>
<head>
<script src="/soap/ajax/10.0/connection.js"></script>
<script type="text/javascript">
function init() {
var who = "phil degauss";
var sstr = "find {" + who + "} in NAME FIELDS RETURNING " +
"Lead (id, firstname, lastname), " +
"Contact(id, firstname, lastname), " +
"Account(id, name)";
107
Chapter 3: Searching and Querying Data
if (sr) {
var list = sr.getArray('searchRecords');
for (var i = 0; i < list.length; i++ ) {
m.innerHTML += "<p>Search results : " +
list[i].toString();
}
} else {
m.innerHTML += "<p>No search results";
}
}
</script>
</head>
<body onload="init();">
<div id="main"></div>
</body>
</html>
Discussion
You can make this solution even more robust by making use of the * wildcard character. For
example, the solution here only searches for exact matches of the name "Phil Degausse." If
you wanted this solution to also return a record named "Philip Degausse," or "Phil Degaussey,"
modify the user's search string by appending * after each token in the string:
Note that it's still important to maintain the space between the two names, so that each token
phil* and degauss* will match individual name fields in the objects that are queried.
See Also
• Choosing Between SOQL and SOSL on page 101
• "Salesforce Object Search Language (SOSL)" at www.salesforce.com/us/developer/
docs/api/index_CSH.htm#sforce_api_calls_sosl.htm
Problem
You want to retrieve records based on a relative date, such as "before last year" or "during the
next fiscal quarter."
Solution
Use a date literal in the WHERE clause of your SOQL or SOSL statement. For example:
108
Retrieving Data Based on a Relative Date
• This SOQL statement returns all opportunities that closed prior to the beginning of the
last fiscal quarter:
SELECT Id FROM Opportunity WHERE CloseDate < LAST_FISCAL_QUARTER
• This SOQL statement returns all opportunities with a close date that is more than 15 days
away:
SELECT Id FROM Opportunity WHERE CloseDate > NEXT_N_DAYS:15
Discussion
When you specify a date in a SOQL or SOSL query, it can be a specific date or dateTime
field, or it can be an expression that uses a date literal—a keyword that represents a relative
range of time such as last month or next year. To construct an expression that returns date or
dateTime values within the range, use =. To construct an expression that returns date or
dateTime values that fall on either side of the range, use > or <.
Salesforce provides date literals such as YESTERDAY, TODAY, LAST_WEEK, NEXT_WEEK. For a
complete list, including examples and range definitions, see "Date Formats and Date Literals"
in the Force Platform Web Services API Developer's Guide at
www.salesforce.com/us/developer
/docs/api/index_CSH.htm#sforce_api_calls_soql_select_dateformats.htm:
Remember that date and dateTime field values are stored as Greenwich Mean Time (GMT)
or Coordinated Universal Time (UTC). When one of these values is returned in Salesforce,
it's automatically adjusted for the time zone specified in your organization preferences.
See Also
• Constructing SOQL and SOSL Queries in the Force Platform Explorer on page 102
• "Salesforce Object Query Language (SOQL)" at www.salesforce.com/us/developer
/docs/api/index_CSH.htm#sforce_api_calls_soql.htm
• "Salesforce Object Search Language (SOSL)" at www.salesforce.com/us/developer
/docs/api/index_CSH.htm#sforce_api_calls_sosl.htm
109
Chapter 3: Searching and Querying Data
Problem
You want to retrieve data for a particular division.
Solution
Use the WITH clause in a SOSL query to filter on division before any other filters are applied.
Although you can also filter on an object's Division field within a WHERE clause, using WITH
is more efficient because it filters all records based on division before applying other filters.
For example:
Notice that the WITH clause filters based on the Division name field, rather than its ID. If
you filter on division in a WHERE clause, you need to use the division ID instead.
See Also
• Constructing SOQL and SOSL Queries in the Force Platform Explorer on page 102
• "Salesforce Object Query Language (SOQL)" at www.salesforce.com/us/developer/
docs/api/index_CSH.htm#sforce_api_calls_soql.htm
• "Salesforce Object Search Language (SOSL)" at www.salesforce.com/us/developer/
docs/api/index_CSH.htm#sforce_api_calls_sosl.htm
Problem
Your solution gives users a chance to build a query or set up a filter for a query that you've
already written. You want to offer users a preview of what data is returned from their query,
including the total number of records that are returned.
Solution
Run two SOQL queries: one that uses COUNT() to return the total number of records that
will be returned, and one that uses LIMIT to quickly return 25 random records that match the
query.
110
Sorting Query Results
Discussion
If your solution allows a user to build a query or set up a filter for an existing query, there's a
chance that the user might execute a long-running query that uses query() or queryMore()
in a loop. This query could easily take a lot longer than the user expects.
To avoid this issue, it's a good idea to give users a preview of their query results if the result
set is going to be greater than 1,000 records, including the total number of records that will
be returned and a sample of what the resulting data will look like. You can then prompt them
with a question such as, "Are you sure?" before proceeding with the full query.
Although running the normal query() call returns the total result size, it also returns a batch
of up to 2,000 records, depending on your configured batch size. If you want your application
to be faster, it's a good idea to run a COUNT() query and a LIMIT query instead.
For example, the following SOQL query returns the total number of accounts in the
organization, without any filters. You can use this value in a prompt to the user to ask if they're
sure they want to proceed with the query:
Then you can use the following SOQL query to return a random subset of the total data to
the user. The user might decide that he or she requires additional fields before the full query
should run:
See Also
• Implementing the Query/Query More Pattern on page 206
• Constructing SOQL and SOSL Queries in the Force Platform Explorer on page 102
• "Salesforce Object Query Language (SOQL)" at www.salesforce.com/us/developer/
docs/api/index_CSH.htm#sforce_api_calls_soql.htm
Problem
You've issued a SOQL or SOSL query and want the results sorted by the value of one or more
fields.
111
Chapter 3: Searching and Querying Data
Solution
Use the ORDER BY clause in your SOQL or SOSL statement to efficiently receive results in
the order that you prefer.
Note: You can't use the ORDER BY clause in any Apex query if it also uses locking.
Those query results, however, are always ordered by ID.
Returns a list of contacts sorted in reverse-alphabetical order by last name and then in
reverse-alphabetical order by first name:
• Andy Young
• Stella Pavlov
• Zebidiah Jazzy
• Jill Jazzy
• Ashley James
• Jack Bond
Returns a list of contacts that include "Ja" in the name, sorted alphabetically by last name:
• Jack Bond
• Ashley James
• Jill Jazzy
112
Sorting Query Results
• Zebidiah Jazzy
Returns a list of contacts and leads that include "Ja" in the name, where contacts are sorted
alphabetically by last name and then reverse-alphabetically by first name, and where leads are
sorted alphabetically by first name:
• (Contact) Jack Bond
• (Contact) Ashley James
• (Contact) Zebidiah Jazzy
• (Contact) Jill Jazzy
• (Lead) Jack Rodgers
• (Lead) Tom Jamison
Discussion
ORDER BY is the best solution for sorting because the Force Platform server does the work and
your code doesn't need to do anything else after receiving the data.
You can sort your query results by any of the specified object's fields that is not a long text area
or multi-select picklist field, even if the field is not one of the query fields that you want
returned.
Note: If you attempt to sort by a long text area or multi-select picklist field, you'll
receive a "malformed query" error message.
The ORDER BY clause for SOQL and SOSL includes a number of features:
• Sort by Multiple Fields
You can sort your query by multiple fields, so that records that have the same value for the
first field are then ordered by the value of a second field. For example, the following query
returns contacts sorted first by LastName and then by FirstName:
113
Chapter 3: Searching and Querying Data
You can specify whether values should be sorted in ascending or descending order by adding
the modifiers ASC or DESC to any sort field. For example, the following query returns
contacts in reverse-alphabetical order:
When this value is not specified, results are sorted in ascending order by default.
ORDER BY always follows the WHERE clause in a SOQL or SOSL statement. For example:
Note: SOQL query sorting is case insensitive. If you require case sensitive sorting,
you'll need to implement this in your own code.
See Also
• Choosing Between SOQL and SOSL on page 101
• Constructing SOQL and SOSL Queries in the Force Platform Explorer on page 102
• "Salesforce Object Query Language (SOQL)" at www.salesforce.com/us/developer/
docs/api/index_CSH.htm#sforce_api_calls_soql.htm
• "Salesforce Object Search Language (SOSL)" at www.salesforce.com/us/developer/
docs/api/index_CSH.htm#sforce_api_calls_sosl.htm
Viewing Tags
Problem
You want to use the API to see all the tags that are available in an organization.
114
View Records with Tags
Solution
Perform the search on the TagDefiniton object to retrieve multiple tags.
The following call will return a list of the public tags in alphabetic order:
sforce.connection.query("SELECT Name FROM TagDefinition WHERE Type =
'Public' ORDER BY Name");
Discussion
Querying TagDefinition does not indicate how many times a tag is being used, nor on what
type of record. To find this information, see View Records with Tags on page 115
See Also
• Updating Tag Definitions on page 232
• "TagDefinition" in the Force Platform Web Services API Developer's Guide at
http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_objects_tagdefinition.htm
Problem
You want to generate a list of records that use the same public tag.
Solution
You can retrieve a list of records with a particular tag by calling queries on specific tag objects.
115
Chapter 3: Searching and Querying Data
For instance, to retrieve a list of all contacts tagged as Staff and all contacts tagged as Great
Lakes, execute the following in the AJAX Toolkit or your own client application:
var staffContactResults = sforce.connection.query("SELECT ItemId FROM
ContactTag WHERE Name = 'Staff'");
var greatLakesContactResults = sforce.connection.query("SELECT ItemId
FROM ContactTag WHERE Name = 'Great Lakes'");
Another example: to find all contacts tagged as both Staff and Great Lakes, use the following
query to form a result array with any null rows dropped:
var ReturnedContacts = sforce.connection.query("SELECT Name, Id, (SELECT
ItemId, Name, Id FROM Tags WHERE Name = 'Staff' OR Name = 'Great
Lakes') FROM Contact");
var TagArray = new Array();
var arraySize = 0;
for (var i = 0; i < ReturnedContacts.size; i++)
{
if (ReturnedContacts.records[i].Tags != null)
{
TagArray[arraySize] = ReturnedContacts.records[i].Tags;
arraySize++;
}
}
See Also
• "TagDefinition" in the Force Platform Web Services API Developer's Guide at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_objects_tagdefinition.htm
• The AJAX Toolkit Developer's Guide at
www.salesforce.com/us/developer/docs/ajax/index.htm
Problem
You'd like to write short, simple queries similar to an outer join in SQL. For example, "retrieve
all the IDs for accounts whose opportunities are all closed.
Solution
Use IN or NOT IN to write simple queries that exploit Salesforce support of semi-joins and
anti-joins in SOQL.
116
Writing Shorter Queries Using Outer Joins
For example, if you want to find the account IDs for all accounts where there is a lost
opportunity associated to the account, use a semi-join:
If you want to find the account IDs for all accounts that have no open opportunities, use an
anti-join query:
SELECT Id
FROM Account
WHERE Id NOT IN (SELECT AcountId FROM Opportunity
WHERE IsClosed = false
)
You can write nested queries using relationships. For example, if you want to find opportunity
IDs and their related line items if the line item value is greater than $10,000, issue a query
similar to the following:
Discussion
Because semi-joins and anti-joins can potentially use a lot of resources during calculation,
salesforce.com enforces some limits on these types of queries. For more information, see
Semi-Joins with IN and Anti-Joins with NOT IN in the Force Platform API Developer's Guide.
See Also
Constructing SOQL and SOSL Queries in the Force Platform Explorer on page 102
117
Chapter 4
Displaying Data and Modifying Data Actions
In this chapter ...
After using recipes in previous chapters that help you modify
• Creating a Many-to-Many the look and feel of Salesforce or inspect existing data, you
Relationship may wish to modify how specific data is presented, or change
the behavior of data actions. Use the recipes in this chapter
• Storing and Displaying
to explore the Force Platform: change how confidential
Confidential Information
information is displayed, change the default behavior of
• Averaging Aggregated bulk processing of records, handling of duplicate records,
Data and many other data display or data action modifications.
• Displaying Fields from a
Related Record on a
Detail Page
• Blocking Record Creation
with Cross-Object
Validation Rules
• Validating Data Based on
Fields in Other Records
• Using Query String
Parameters in a
Visualforce Page
• Using AJAX in a
Visualforce Page
• Using Properties in Apex
• Mass Updating Contacts
When an Account
Changes
• Bulk Processing Records
in a Trigger
119
Chapter 4: Displaying Data and Modifying Data Actions
• Controlling Recursive
Triggers
• Comparing Queries
Against Trigger.old and
Trigger.new
• Preventing Duplicate
Records from Saving
• Creating a Child Record
When a Parent Record is
Created
• Using System.runAs in
Test Methods
120
Creating a Many-to-Many Relationship
Problem
You want to model a many-to-many relationship between objects in which each record of one
object can be related to many records of the other object, and vice versa. For example, a customer
case can require many bug fixes, and a bug fix can resolve multiple customer cases.
Note: This recipe has been provided by salesforce.com Training & Certification and
is drawn from the expert-led training courses available around the world. Salesforce.com
training courses provide an opportunity to get hands-on experience with the Force
Platform and Salesforce applications as well as to prepare you to become Salesforce.com
Certified. Register for a course at www.salesforce.com/training.
Solution
Relate the two objects using a custom junction object, and customize the junction object related
lists and reports. A custom junction object is an object with two master-detail relationships.
Its purpose is to create an association between two other objects. For example, a many-to-many
relationship between bugs and cases uses a custom junction object called BugCaseAssociation
to associate the Bug and Case objects.
121
Chapter 4: Displaying Data and Modifying Data Actions
• Name the object with a label that indicates its purpose, such as
BugCaseAssociation.
• For the Record Name field, use the auto-number data type.
• Do not launch the custom tab wizard before clicking Save. Junction objects do
not need a tab.
3. On the junction object, create the second master-detail relationship. In the custom
field wizard:
122
Creating a Many-to-Many Relationship
To customize the fields that display in the junction object related list on each master object
page layout:
1. Edit the page layout of each master object that is related to the junction object. For
example, to modify the BugCaseAssociations related list for case records, edit the
page layout for cases at Setup ➤ Customize ➤ Cases ➤ Page Layouts.
2. Select the related list you want to modify and click Edit Properties to open the
related list popup window. For example, on cases the BugCaseAssociations related
list was renamed to Bugs, so select the Bugs related list.
3. Add the fields to display in the related list. You can add fields from the junction
object itself, but more importantly, you can add fields from the other master object.
Each field is prefixed with its object name in the popup window. In the related list
itself, only fields from the junction object are prefixed with the object name; fields
from the other master object are not.
Note: The junction object related list does not include an icon on the master record's
detail pages because the junction object does not have a custom tab. If you make a tab
for the junction object, the icon is included.
Discussion
For a many-to-many relationship in Salesforce, each master object record displays a related
list of the associated junction object records. To create a seamless user experience, you can
change the name of the junction object related list on each of the master object page layouts
123
Chapter 4: Displaying Data and Modifying Data Actions
to have the name of the other master object. For example, you might change the
BugCaseAssociations related list to Cases on the bugs page layout and to Bugs on the cases
page layout. You can further customize these related lists to display fields from the other master
object.
Many-to-many relationships provide two standard report types that join the master objects
and the junction object. The report types are:
• "Primary master with junction object and secondary master" in the primary master object's
report category
• "Secondary master with junction object and primary master" in the secondary master object's
report category
The order of the master objects in the report type is important. The master object listed first
determines the scope of records that can be displayed in the report.
You can create custom reports based on these standard report types. In addition, you can create
custom report types to customize which related objects are joined in the report.
See Also
• "Considerations for Relationships" in the Salesforce online help
124
Storing and Displaying Confidential Information
Problem
You want to store employee Social Security numbers as encrypted data as required by
government regulations or industry standards. Only select certain users should be able to view
the entire social security number; all other users should only be able to view the last four digits.
In addition, you want to ensure that users enter the numbers in the standard social security
number format, including the dashes after the third and fifth digits.
Solution
On the standard user object, create an encrypted custom field to store the user's Social Security
number. Set the field's Mask Type attribute to hide the first five digits of the social security
number, and add field-level help to inform users of the required format. Then, create a validation
rule that uses the REGEX() function to verify that the value of the custom field is in the correct
format. Finally, create a new custom profile that allows a select group of users to the see the
Social Security numbers unmasked.
Note: To enable encrypted fields for your organization, contact salesforce.com
Customer Support.
125
Chapter 4: Displaying Data and Modifying Data Actions
permission selected are able to view all nine digits of the Social Security
number.
i. In the Mask Character field, select the character, either an asterisk (*)
or an X, to use for hidden characters.
j. Click Next.
k. In Enterprise, Unlimited, and Developer Editions, set the field-level security
to determine whether the field should be visible or read only for specific
profiles. These settings determine whether or not the field itself is visible,
but do not affect whether or not the user sees the masked or full Social
Security number. You will specify the type of masking when you create the
custom profile.
l. Click Next.
m. Leave the Add Field and User Layout checkboxes selected.
n. Click Save.
126
Storing and Displaying Confidential Information
4. Assign the new custom profile to the users allowed to view the encrypted data.
Discussion
Government regulations and industry standards require many companies to use encryption to
protect their most sensitive employee and customer data. Encrypted custom fields can help
companies comply with these regulations. Salesforce encrypts these fields with 128-bit keys
and uses the AES (Advanced Encryption Standard) algorithm which has been adopted as an
encryption standard by the U.S. government. Encrypted custom fields should only be used
when regulations require encryption because they involve additional processing and have
search-related limitations.
To further protect the confidentiality of encrypted custom field values, Salesforce requires you
to specify a mask type for each encrypted field you create. Character masking lets you hide the
characters in encrypted field values, allowing users to see the full value of an encrypted custom
field only if their profile has the "View Encrypted Data" permission. If your company uses
parts of confidential data, such as the last four digits of a person's Social Security or credit card
number, to verify the identity of customers, configure your encrypted custom fields to use a
mask type that reveals only the those digits, such as the Last Four Characters Clear
mask type.
In addition to ensuring your data's confidentiality, you also want to ensure its accuracy.
Validation rules improve the quality of your data by verifying that the data a user enters in a
record meets the standards you specify before the user can save the record. A validation rule
contains a formula expression that evaluates the data in one or more fields and returns a value
of "True" or "False." If the validation rule returns "True," Salesforce lets the user save the
record; otherwise, Salesforce displays an error message.
The validation rule in this recipe uses the REGEX() function, which compares the custom field
to a regular expression. A regular expression is a string used to describe a format of a string
according to certain syntax rules. Salesforce regular expression syntax is based on Java Platform
SE 6 syntax; however, backslash characters (\) must be changed to double backslashes (\\)
because backslash is an escape character in Salesforce.
127
Chapter 4: Displaying Data and Modifying Data Actions
See Also
• Validating Data Based on Fields in Other Records on page 136
• "About Validation Rules" in the Salesforce online help
• "Operators and Functions" in the Salesforce online help
• "About Encrypted Custom Fields" in the Salesforce online help
Problem
You want to calculate the average value of a numeric field on a set of detail records in a
master-detail relationship.
Note: This recipe has been provided by salesforce.com Training & Certification and
is drawn from the expert-led training courses available around the world. Salesforce.com
training courses provide an opportunity to get hands-on experience with the Force
Platform and Salesforce applications as well as to prepare you to become Salesforce.com
Certified. Register for a course at www.salesforce.com/training.
Solution
Create two roll-up summary fields: one that sums a numeric field on a detail record and another
that counts the number of detail records. Then use a formula field that divides the first roll-up
summary field by the second.
To illustrate this example, we'll look at the Job Application and Review objects in the sample
Recruiting application. The Job Application object is the master in a master-detail relationship
with the Review object. The Review object has a 1-5 rating system. We want to display the
average rating on the job application.
128
Averaging Aggregated Data
8. Click Next.
9. Configure the remaining field-level security and page layout settings as desired.
10. Click Save.
129
Chapter 4: Displaying Data and Modifying Data Actions
Discussion
Roll-up summary fields let you easily display values from a set of detail records. Use roll-up
summary fields to display the total number of detail records, the sum of all the values in a detail
record field, or the highest or lowest value of a detail field.
Before you begin working with roll-up summary fields, note that they are only available on the
master object in a master-detail relationship.
When working with merge fields in formulas, use the IF function to ensure that the formula
field displays correctly even if they have an invalid value. (For example, an invalid value may
occur if the formula divides by zero.) The IF function in this recipe ensures that the formula
displays a value when there are one or more reviews, and displays a zero if there are no reviews;
otherwise, the formula field might display #Error.
See Also
• Blocking Record Creation with Cross-Object Validation Rules on page 133
• "About Roll-Up Summary Fields" in the Salesforce online help
• "Useful Advanced Formula Fields" in the Salesforce online help
• "Considerations for Relationships" in the Salesforce online help
Problem
You want to show field values from a related object on a detail page.
Solution
Use a cross-object formula field to retrieve and display the field values from a related object.
To illustrate this example, we'll look at the Review object in the sample Recruiting application.
The Review object is the detail record of the Job Application object. The Job Application
object has lookup relationships to the Position and Candidate objects. Using cross-object
formulas, we will display the title of the related position and the name of the related candidate
on each review record.
130
Displaying Fields from a Related Record on a Detail Page
5. In the Field Label field, enter Position. Once you move your cursor, the Field
Name text box should be automatically populated with Position.
6. Select the Text formula return type and click Next.
7. Click the Advanced Formula tab.
Note: You can create cross-object formulas only on the Advanced Formula
tab.
The Review object now displays the value of the Position Title field from the related
position record. Next, create a cross-object formula field on the Review object that displays
the first and last names of the candidate being reviewed, and we'll use the HYPERLINK function
so that users can access the candidate's record by clicking the formula field.
131
Chapter 4: Displaying Data and Modifying Data Actions
This appends a blank space after the first name of the candidate.
15. Enter a space, click the Insert Operator button, and choose Concatenate once more
to add a second ampersand in your formula.
16. Click the Insert Field button, select Review >, Job Application >, Candidate
>, and Last Name, then click Insert.
17. Delete [ target ] from the HYPERLINK function. This is an optional parameter
that isn't necessary for our formula field.
18. Click Check Syntax to check your formula for errors.
Your finished formula should look like this:
HYPERLINK( Job_Application__r.Candidate__r.Id ,
Job_Application__r.Candidate__r.First_Name__c & " " &
Job_Application__r.Candidate__r.Last_Name__c )
Discussion
Cross-object formulas are formulas that span two or more objects by referencing merge fields
from related records. They are available anywhere you can use formulas except for default values
and summary reports. Use them in calculations or simply to display fields from related objects
on detail pages, list views, related lists, and reports.
Each formula can reference up to five related objects, and can span to an object that is five
relationships away. For example, consider the following formula we created in the first set of
solution steps:
Job_Application__r.Position__r.Name
132
Blocking Record Creation with Cross-Object Validation Rules
This formula spans two relationships: first it spans to the review's related job application
(Job_Application__r), then to the job application's related position (Position__r). The
formula ultimately references the position's title (Name) on the Position object. Notice that
each part of the formula is separated by a period, and that the relationship names consist of
the related object followed by __r.
In the second cross-object formula field we created, we used the Concatenate (&) operator to
join two separate fields (First_Name__c and Last_Name__c) and inserted a space between
them. We also used the HYPERLINK function, which lets you to create a hyperlink to any URL
or record in Salesforce. Note that the label of the hyperlink can differ from the URL itself,
which is especially useful when working with a cross-object formula field that displays a value
that a user will want to click. In this recipe, we used the HYPERLINK function to let users
conveniently access the candidate's record by clicking the Candidate's Name field on the
Review object.
See Also
• Validating Data Based on Fields in Other Records on page 136
• Averaging Aggregated Data on page 128
• The Sample Recruiting App on page 3
• "About Formulas" in the Salesforce online help
• "Useful Advanced Formula Fields" in the Salesforce online help
• "Formulas: How Do I..." in the Salesforce online help
• "Operators and Functions" in the Salesforce online help
Problem
You want to prevent a subset of users from saving a record if certain conditions exist on a
related record.
For example, the Recruiting app has the following custom objects:
• Employment Website Information about the cost of posting a position on a particular
employment website, such as Monster.com, and the budget the company has allocated for
posting on that website.
• Position An open employment opportunity in the company.
• Job Posting A custom junction object between the Employment Website and Position
objects that represents a single posting on an employment website.
133
Chapter 4: Displaying Data and Modifying Data Actions
You want to prevent users from creating a Job Posting record if the record will cause the
company to go over its budget for an employment website unless the position was created by
the CEO.
Note: This recipe has been provided by salesforce.com Training & Certification and
is drawn from the expert-led training courses available around the world. Salesforce.com
training courses provide an opportunity to get hands-on experience with the Force
Platform and Salesforce applications as well as to prepare you to become Salesforce.com
Certified. Register for a course at www.salesforce.com/training.
Solution
Create a cross-object validation rule on the Job Posting object that references one roll-up
summary field and two currency fields on the Employment Website object.
Create the currency field that stores the price per post.
134
Blocking Record Creation with Cross-Object Validation Rules
9. Configure the remaining field-level security and page layout settings as desired.
10. Click Save.
6. In the Error Message field, enter You have exceeded the budget for
posting on this employment website.
7. In the Error Location field, select Top of Page.
8. Click Save.
135
Chapter 4: Displaying Data and Modifying Data Actions
Discussion
The first part of the validation rule formula spans to the Positions object to verify that the user
who created the position is not the CEO. This gives users the flexibility of going over budget
on job postings for positions that the CEO has created.
The second part of the validation rule formula spans to the Employment Website object to
retrieve three values that are essential to the calculation. First, the formula references the roll
up summary field to count how many Job Posting records have been saved for the associated
Employment Website record. Then the formula references the currency field that stores the
price per post, and multiplies this value by the job record count to anticipate what the total
amount spent on this website will be if the job posting is saved. Finally, the formula references
the currency field that stores the maximum budget, and subtracts the price per post from this
value. Subtracting the price per post from the maximum budget compensates for the fact that
Salesforce cannot determine if the record exceeds the budget until after the record is saved.
See Also
• Validating Data Based on Fields in Other Records on page 136
• Averaging Aggregated Data on page 128
• The Sample Recruiting App on page 3
• "About Validation Rules" in the Salesforce online help
• "About Roll-Up Summary Fields" in the Salesforce online help
• "Useful Advanced Formula Fields" in the Salesforce online help
• "Considerations for Relationships" in the Salesforce online help
Problem
You want to validate a candidate's ZIP code before saving a candidate record.
Solution
On the Candidate object in the Recruiting app, create a validation rule that uses the VLOOKUP()
function to verify the value of the ZIP Code field against a list of valid ZIP codes stored on
a custom object.
1. Create a custom object called ZIP Code with the following settings:
Field Value
Label ZIP Code
136
Validating Data Based on Fields in Other Records
Field Value
Plural Label ZIP Codes
Object Name ZIP_Code
Description Represents a ZIP code
Context-Sensitive Help Setting Open the standard Salesforce Help &
Training window
Record Name ZIP Code
Data Type Text
Allow Reports No
Allow Activities No
Track Field History No
Deployment Status Deployed
Add Notes & Attachments related No
list to default page layout
3. Create a validation rule on the Candidate object that uses the following formula:
LEN(ZIP_Code__c) > 0 &&
(Country__c = "USA" || Country__c = "US") &&
VLOOKUP(
$ObjectType.ZIP_Code__c.Fields.City__c,
$ObjectType.ZIP_Code__c.Fields.Name,
LEFT(ZIP_Code__c,5))
137
Chapter 4: Displaying Data and Modifying Data Actions
<> City__c
)
Set the Error Message to The ZIP Code you entered is incorrect.
Discussion
The VLOOKUP() function returns a value by looking up a related value on a custom object. In
this recipe, the validation rule uses the VLOOKUP() function to search the Name field on all
the ZIP code records. It searchesuntil it finds one that matches the value of the ZIP Code
field on the candidate record that the user is trying to save. After finding the matching ZIP
code record, the VLOOKUP() function checks the record's City field to see if it is not equal to
the City field on the candidate record. If the search for a matching ZIP code record is
unsuccessful, or if the values of the City fields on either record do not match, the validation
rule prevents the candidate record from being saved, and returns the message The ZIP Code
you entered is incorrect.
See Also
• "About Validation Rules" in the Salesforce online help
• Storing and Displaying Confidential Information on page 125
• "Operators and Functions" in the Salesforce online help
138
Using Query String Parameters in a Visualforce Page
Problem
You want to read and set query string parameters in a Visualforce page, either in a custom
controller or in the page itself.
Solution
The way to read and set query string parameters depends on whether you access them from a
custom controller or directly from a Visualforce page.
• If you're writing a custom controller, use the ApexPages global object variable and
currentPage() and getParameters() methods to get query string parameters. For
example, to get the value of the name query parameter in the URL:
https://na1.salesforce.com/001/e?name=value, use the following line in your
custom controller:
String value = ApexPages.currentPage().getParameters().get('name');
• If you're editing a page, use the $PageContext global variable in a merge field.
For example, suppose you want to add the Open Activities related list to an account detail
page, but instead of showing the account's activities, you want to show the activities of a
specified contact. To specify the contact, the following page looks for a query string
parameter for the contact's ID under the name relatedId:
<apex:page standardController="Account">
<apex:pageBlock title="Hello {!$User.FirstName}!">
You belong to the {!account.name} account.<br/>
You're also a nice person.
</apex:pageBlock>
<apex:detail subject="{!account}" relatedList="false"/>
<apex:relatedList list="OpenActivities"
subject="{!$CurrentPage.parameters.relatedId}"/>
</apex:page>
For this related list to render in a saved page, valid account and contact IDs must be specified
in the URL. For example, if 001D000000HRgU6 is the account ID and 003D000000OXDIx
is the contact ID, use the URL
139
Chapter 4: Displaying Data and Modifying Data Actions
https://na3.salesforce.com/apex/MyFirstPage?id=001D000000HRgU6&
relatedId=003D000000OXDIx.
Search Google
</apex:outputLink>
Or you can use the <apex:param> tag as a child tag to write cleaner code:
<apex:outputLink value="http://google.com/search">
Search Google
<apex:param name="q" value="{!account.name}"/>
</apex:outputLink>
See Also
• Building a Table of Data in a Visualforce Page on page 31
• Building a Form in a Visualforce Page on page 33
• Creating a Wizard with Visualforce Pages on page 35
• Using AJAX in a Visualforce Page on page 141
140
Using AJAX in a Visualforce Page
Problem
You want to use AJAX in a Visualforce page so that only part of the page needs to be refreshed
when a user clicks a button or link.
Solution
Use the reRender attribute on an <apex:commandLink> or <apex:commandButton> tag
to identify the component that should be refreshed. When a user clicks the button or link, only
the identified component and all of its child components are refreshed.
For example, the following page shows a list of contacts. When a user clicks the name of a
contact, only the area below the list refreshes, showing the details for the contact:
Figure 20: Developers Can Use Embedded AJAX to Refresh Part of a Page
The following markup defines the page from the previous example:
141
Chapter 4: Displaying Data and Modifying Data Actions
The following markup defines the Apex controller class for the page. It includes two methods:
one to return a list of the ten most recently modified contacts and one to return a single contact
record based on the id query parameter of the page URL:
// Get the 'id' query parameter from the URL of the page.
// If it's not specified, return an empty contact.
// Otherwise, issue a SOQL query to return the contact from the
// database.
public Contact getContact() {
Id id = System.currentPageReference().getParameters().get('id');
142
Using Properties in Apex
See Also
• Using Query String Parameters in a Visualforce Page on page 139
• Building a Table of Data in a Visualforce Page on page 31
• Building a Form in a Visualforce Page on page 33
• Creating a Wizard with Visualforce Pages on page 35
Problem
You want to create a page that captures input from users, and that input spans multiple sObjects.
Solution
Use a Visualforce page with a custom Apex controller, and give it properties to represent the
input fields from Accounts and Contacts.
143
Chapter 4: Displaying Data and Modifying Data Actions
2. Update the controller by replacing the line // Add properties here with the
following Apex properties:
public String companyName {get; set;}
public Integer numEmployees {get; set;}
public String streetAddress {get; set;}
public String cityAddress {get; set;}
public String stateAddress {get; set;}
public String postalCodeAddress {get; set;}
public String countryAddress {get; set;}
public String department {get; set;}
public String email {get; set;}
public String phone {get; set;}
public String firstName {get; set;}
public String lastName {get; set;}
public String title {get; set;}
insert a;
144
Using Properties in Apex
MailingCity = cityAddress,
MailingState = stateAddress,
MailingPostalCode = postalCodeAddress,
MailingCountry = countryAddress);
insert c;
}
7. Click Save.
8. Click SetupDevelop ➤ Pages.
9. Click New.
10. In the name field, enter newCustomerEntry.
11. Optionally enter a label and description.
12. In the editor, enter the following markup:
<apex:page controller="Customer">
<apex:form >
<apex:pageBlock title="New Customer Entry">
<p>First Name:
<apex:inputText value="{!firstName}"/></p>
<p>Last Name:
<apex:inputText value="{!lastName}"/></p>
<p>Company Name:
<apex:inputText value="{!companyName}"/></p>
<p># Employees:
<apex:inputText value="{!numEmployees}"/></p>
<p>Department:
<apex:inputText value="{!department}"/></p>
<p>Email:
<apex:inputText value="{!email}"/></p>
<p>Phone:
<apex:inputText value="{!phone}"/></p>
145
Chapter 4: Displaying Data and Modifying Data Actions
<p>Title:
<apex:inputText value="{!title}"/></p>
<p>Address</p>
<p>Street:
<apex:inputText value="{!streetAddress}"/></p>
<p>City:
<apex:inputText value="{!cityAddress}"/></p>
<p>State:
<apex:inputText value="{!stateAddress}"/></p>
<p>Zip:
<apex:inputText
value="{!postalCodeAddress}"/></p>
<p>Country:
<apex:inputText value="{!countryAddress}"/></p>
<p><apex:commandButton action="{!save}"
value="Save New Customer"/></p>
</apex:pageBlock>
</apex:form>
<!-- Add related lists here -->
</apex:page>
<apex:column value="{!acct.Name}"/>
<apex:column value="{!acct.NumberOfEmployees}"/>
</apex:pageBlockTable>
</apex:pageBlock>
<apex:pageBlock title="Contacts">
<apex:pageBlockTable value="{!contactList}" var="item">
<apex:column value="{!item.Name}"/>
<apex:column value="{!item.Phone}"/>
<apex:column value="{!item.Title}"/>
<apex:column value="{!item.Department}"/>
<apex:column value="{!item.Email}"/>
</apex:pageBlockTable>
</apex:pageBlock>
146
Mass Updating Contacts When an Account Changes
Discussion
You want to ask the user to enter information about a new customer. The fields are used to
create both a new account and a new contact associated with that account. Using a Visualforce
page lets you present whatever user interface you want, using HTML and Visualforce markup;
however, each standard controller in Visualforce corresponds to a single sObject type, such as
Account or Contact. To work with more than on sObject type, you need to use a custom
controller.
When using a Apex custom controller, the easiest way to do to access data on exposed by the
controller is to use Apex properties. The syntax for Apex properties is similar to C# properties.
Java-style bean properties (with getters and setters that you create for each property) also work;
however, the property syntax used above is much more readable, and makes it easier to
distinguish the controller's properties from its actions.
Queries in a custom controller can be used to present data to the user. In this example, queries
are used to create two tables that mimic related lists.
Since the form is simple HTML, you can modify it to your style either using HTML or
Visualforce components.
Note that when you add a new customer and click Save, the account and contact information
is displayed in the related lists on the page.
See Also
• Creating a Child Record When a Parent Record is Created on page 160
• Using Dynamic Apex on page 73
Problem
You want to update the address of all contacts associated with an account whenever the account's
address changes.
Solution
Write a trigger in Apex that updates associated contacts when an account is updated. For
example:
147
Chapter 4: Displaying Data and Modifying Data Actions
// new addresses
Map<Id, Account> acctsWithNewAddresses = new Map<Id, Account>();
c.MailingCity = parentAccount.ShippingCity;
c.MailingCountry = parentAccount.ShippingCountry;
c.MailingPostalCode = parentAccount.ShippingPostalCode;
c.MailingState = parentAccount.ShippingState;
c.MailingStreet = parentAccount.ShippingStreet;
See Also
• Creating a Child Record When a Parent Record is Created on page 160
• Bulk Processing Records in a Trigger on page 149
148
Bulk Processing Records in a Trigger
Problem
You're new to writing triggers, and when you write one for bulk processing, it often runs into
Apex governor limits.
Solution
For efficient bulk processing, it's critical that triggers execute a constant number of database
queries, regardless of how many records are being processed. Instead of looping over individual
records in the Trigger.old or Trigger.new lists, use maps to organize records based on
their ID or another identifying field, and use sets to isolate distinct records.
For example, consider the following lead deduplication trigger, which rejects any new or updated
lead that has a duplicate email address:
• The trigger first uses a map to store the updated leads with each lead's email address as the
key.
• The trigger then uses the set of keys in the map to query the database for any existing lead
records with the same email addresses. For every matching lead, the duplicate record is
marked with an error condition.
"Bulk Processing Records in a Trigger" contributed by Steve Fisher, Senior Vice President of the
Platform Division for salesforce.com
149
Chapter 4: Displaying Data and Modifying Data Actions
leadMap.put(lead.Email, lead);
}
}
}
See Also
• Preventing Duplicate Records from Saving on page 154 contains further discussion of the
Apex trigger in this recipe.
• Controlling Recursive Triggers on page 150
Problem
You want to write a trigger that creates a new record as part of its processing logic; however,
that record may then cause another trigger to fire, which in turn causes another to fire, and so
on. You don't know how to stop that recursion.
Solution
Use a static variable in an Apex class to avoid an infinite loop. Static variables are local to the
context of a Web request (or test method during a call to runTests()), so all triggers that
fire as a result of a user's action have access to it.
For example, consider the following scenario: frequently a Salesforce user wants to follow up
with a customer the day after logging a call with that customer. Because this is such a common
use case, you want to provide your users with a helpful checkbox on a task that allows them to
automatically create a follow-up task scheduled for the next day.
You can use a before insert trigger on Task to insert the follow-up task, but this, in turn,
refires the before insert trigger before the follow-up task is inserted. To exit out of this
recursion, set a static class boolean variable during the first pass through the trigger to inform
the second trigger that it should not insert another follow-up task:
150
Controlling Recursive Triggers
Note: For this Apex script to work properly, you first must define a custom checkbox
field on Task. In this example, this field is named Create_Follow_Up_Task__c.
The following code defines the class with the static class variable:
151
Chapter 4: Displaying Data and Modifying Data Actions
followUpTask.subject =
FollowUpTaskHelper.getFollowUpSubect(followUpTask.subject);
if (followUpTask.ActivityDate != null) {
followUpTask.ActivityDate =
followUpTask.ActivityDate + 1; //The day after
}
followUpTasks.add(followUpTask);
}
}
FollowUpTaskHelper.setAlreadyCreatedFollowUpTasks();
insert followUpTasks;
}
}
insert tasksToCreate;
System.assertEquals(NUMBER_TO_CREATE,
[select count()
from Task
where subject = :UNIQUE_SUBJECT
and ActivityDate = :System.today()]);
152
Comparing Queries Against Trigger.old and Trigger.new
ActivityDate = System.today(),
Create_Follow_Up_Task__c = false);
tasksToCreate.add(newTask);
}
insert tasksToCreate;
System.assertEquals(NUMBER_TO_CREATE,
[select count()
from Task
where subject=:UNIQUE_SUBJECT
and ActivityDate =:System.today()]);
See Also
• Bulk Processing Records in a Trigger on page 149
• Comparing Queries Against Trigger.old and Trigger.new on page 153
Problem
You're writing a before update or before delete trigger and need to issue a SOQL
query to get related data for records in the Trigger.new and Trigger.old lists.
Solution
Correlate records and query results with the Trigger.newMap and Trigger.oldMap
ID-to-SObject maps.
For example, the following trigger uses Trigger.oldMap to create a set of unique IDs
(Trigger.oldMap.keySet()). The set is then used as part of a query to create a list of job
applications associated with the candidates being processed by the trigger. For every job
153
Chapter 4: Displaying Data and Modifying Data Actions
application returned by the query, the related candidate is retrieved from Trigger.oldMap
and prevented from being deleted.
Trigger.oldMap.get(jobApp.Candidate__c).addError(
'Cannot delete candidate with a job application');
}
}
Discussion
It's a better practice to use Trigger.newMap and Trigger.oldMap because you can't assume
that directly querying the Trigger.new and Trigger.old lists will return the same number
of records in the same order. Even though these lists are sorted by ID, external operations
might change the number of records that are returned and make parallel list processing
dangerous.
See Also
• Bulk Processing Records in a Trigger on page 149
• Controlling Recursive Triggers on page 150
Problem
You want to prevent users from saving duplicate records based on the value of one or more
fields.
Solution
If you can determine whether a record is a duplicate based on the value of a single custom field,
select the Unique and Required checkboxes on that field's definition:
"Preventing Duplicate Records from Saving" contributed by Steve Fisher, Senior Vice President of
the Platform Division for salesforce.com
154
Preventing Duplicate Records from Saving
2. Select the link for the desired object, and click Fields.
3. Click Edit next to the name of the appropriate field.
The Unique and Required checkboxes are only available on custom fields. If you want to
check for uniqueness based on the value of a single standard field and your edition can't use
Apex, you can also use the following workaround:
1. Create a custom field with the same type and label as the standard field. Select the
Unique and Required checkboxes on the custom field's definition page.
2. Replace the standard field with your new custom field on all page layouts.
3. Use field-level security to make the standard field read-only for all user profiles. This
prevents any user from mistakenly modifying the standard field through the API,
unless the user has the "Modify All Data" profile permission.
4. Define a workflow rule that automatically updates the value of the standard field
with the value of the custom field whenever the custom field changes. This ensures
that any application functionality that relies on the value of the standard field
continues to work properly. (For example, the Send An Email button on the Activity
History related list relies on the standard Email field for a lead or contact.)
Note: Because this is a less-elegant solution than using Apex, creating a trigger on
lead is the preferred solution for Unlimited Edition and Developer Edition.
If you need to require uniqueness based on the value of two or more fields, or a single standard
field, write an Apex before insert and before update trigger. For example, the following
trigger prevents leads from being saved if they have a matching Email field:
• The trigger first uses a map to store the updated leads with each lead's email address as the
key.
• The trigger then uses the set of keys in the map to query the database for any existing lead
records with the same email addresses. For every matching lead, the duplicate record is
marked with an error condition.
155
Chapter 4: Displaying Data and Modifying Data Actions
The following class can be used to test the trigger for both single- and bulk-record inserts and
updates.
// Seed the database with some leads, and make sure they can
// be bulk inserted successfully.
Lead lead1 = new Lead(LastName='Test1', Company='Test1 Inc.',
Email='[email protected]');
Lead lead2 = new Lead(LastName='Test2', Company='Test2 Inc.',
Email='[email protected]');
Lead lead3 = new Lead(LastName='Test3', Company='Test3 Inc.',
Email='[email protected]');
Lead[] leads = new Lead[] {lead1, lead2, lead3};
insert leads;
156
Preventing Duplicate Records from Saving
// Now make sure that some of these leads can be changed and
// then bulk updated successfully. Note that lead1 is not
// being changed, but is still being passed to the update
// call. This should be OK.
lead2.Email = '[email protected]';
lead3.Email = '[email protected]';
update leads;
157
Chapter 4: Displaying Data and Modifying Data Actions
158
Preventing Duplicate Records from Saving
Email='[email protected]');
dups = new Lead[] {dup1, dup2, dup3};
try {
insert dups;
System.assert(false);
} catch (DmlException e) {
System.assert(e.getNumDml() == 2);
System.assert(e.getDmlIndex(0) == 1);
System.assert(e.getDmlFields(0).size() == 1);
System.assert(e.getDmlFields(0)[0] == 'Email');
System.assert(e.getDmlMessage(0).indexOf(
'Another new lead has the same email address.') > -1);
System.assert(e.getDmlIndex(1) == 2);
System.assert(e.getDmlFields(1).size() == 1);
System.assert(e.getDmlFields(1)[0] == 'Email');
System.assert(e.getDmlMessage(1).indexOf(
'A lead with this email address already exists.') > -1);
}
Discussion
The first and most important lesson to learn from this recipe is that you should generally take
advantage of native Force Platform functionality if it can solve your problem, rather than
writing code. By using the point-and-click tools that are provided, you leverage the power of
the platform. Why reinvent the wheel if you can take advantage of a native feature that performs
the same functionality? As a result, we indicate in this recipe that you should first determine
whether you can simply use the Unique and Required checkboxes on a single custom field
definition to prevent duplicates.
159
Chapter 4: Displaying Data and Modifying Data Actions
If you do need to check for duplicates based on the value of a single standard field, or more
than one field, Apex is the best way to accomplish this. Because Apex runs natively on the
Force Platform servers, it's far more efficient than a deduplication algorithm that runs in an
s-control or Web control. Additionally, Apex can execute every time a record is inserted or
updated in the database, regardless of whether the database operation occurs as a result of a
user clicking Save in the user interface, or as a result of a bulk upsert call to the API. S-controls
and Web controls can only be triggered when a record is saved through the user interface.
See Also
Controlling Recursive Triggers on page 150
Problem
You want to automatically create a new child record when you create a parent record. The
child record should be populated with default values from the position.
Solution
Use an Apex trigger to automatically create the child record when a new parent record is
created.
For this example, let's automatically create a new interviewer record (child) for the specified
hiring manager whenever a new position (parent) is created.
160
Using System.runAs in Test Methods
if (newPosition.Hiring_Manager__c != null) {
interviewers.add(new Interviewer__c(
Name = '1',
Position__c = newPosition.Id,
Employee__c = newPosition.Hiring_Manager__c,
Role__c = 'Managerial'));
}
}
insert interviewers;
}
See Also
• Bulk Processing Records in a Trigger on page 149
• Controlling Recursive Triggers on page 150
• Comparing Queries Against Trigger.old and Trigger.new on page 153
Problem
Generally, all Apex scripts run in system mode. The permissions and record sharing of the
current user are not taken into account; however, you need to verify if a specific user has access
to a specific object.
Solution
The system method runAs enables you to write test methods that change user contexts to
either an existing user or a new user. All of that user's record sharing is then enforced.
In the following example, a new user is created, based on the standard user profile. In addition,
a second user is instantiated, based on the system administrator profile, to demonstrate both
ways of generating users for tests. Two accounts are created, and then runAs verifies that the
standard user cannot view the administrator account.
@isTest
private class MyTestClass {
// Retrieve two profiles, for the standard user and the system
161
Chapter 4: Displaying Data and Modifying Data Actions
for(Profile p : ps){
profiles.put(p.name, p.id);
}
insert standard;
accnts.add(a1);
accnts.add(a2);
insert accnts;
// Confirm that the standard user cannot see the admin account
system.runas(standard){
accnts.clear();
accnts = [select id, name from account where id = :a1.id];
system.debug(accnts.isEmpty() + ' really'+accnts);
System.assertEquals(accnts.isEmpty(), true);
}
// Confirm that the admin user can see the standard account
system.runas(admin){
accnts.clear();
accnts = [select id, name from account where id = :a2.id];
System.assertEquals(accnts.isEmpty(), false);
}
162
Using System.runAs in Test Methods
}
}
Discussion
Note that this class is defined as isTest. Classes defined with the isTest annotation do not
count against your organization limit of 1 MB for all Apex scripts.
Only the following items use the permissions granted by the user specified with runAs:
• dynamic Apex
• methods using with sharing or without sharing
• shared records
See Also
"Testing and Code Coverage" in the Apex Language Reference available at
www.salesforce.com/us/developer/docs/apexcode/index_CSH.htm#apex_testing.htm
163
Chapter 5
Integrating with other Applications
In this chapter ...
You can integrate the operation of other applications with
• Retrieving Sender Salesforce in a number of ways. This chapter contains
Information recipes for integration using email messaging, mobile
applications, and delegated authentication.
• Retrieving Attachments
from an Email
Working with Email in Salesforce
• Creating a New Contact
from an Email By utilizing Apex classes, functions, and interfaces,
• Sending an Automatic Salesforce provides you with numerous ways to automate
Email inbound and outbound message processing.
• Activating Email Services In this chapter, you'll learn how you can use Apex to retrieve
• Using Visualforce Email contact information from a sender, determine whether an
Templates attachment is valid, and create a new contact based on
• Using Apex to Update received information. You will also learn how to send an
Salesforce Data in the automated reply, and use Visualforce to create powerful
Mobile Application email templates.
• Retrieving a User's
Location from a Integrating with the Mobile Application
GPS-enabled BlackBerry You can access and manipulate Salesforce data from your
Smartphone mobile device using the Mobile application.
• Enabling Single Sign-On
with the Force Platform Integrating with Delegated Authentication
You can create a delegated authentication application to
manage single sign-on.
165
Chapter 5: Integrating with other Applications
Problem
You want to store the name, email address, and other contact information about a user that
sends you an email.
Note: For the code sample in this Solution to work, you must have the Recruiting
app metadata in your organization. See The Sample Recruiting App on page 3.
Solution
Create an Apex class that implements the InboundEmailHandler interface. For example:
global class ProcessApplicant implements Messaging.InboundEmailHandler
For every email received by Salesforce, an InboundEmail object is created that contains the
contents and attachments of the email. To work with the object, the class needs to define the
handIeInboundEmail method. For example:
Note: The complete method is listed at the end of Sending an Automatic Email on
page 171. Use the complete sample for testing.
To continue the implementation, we need to set up a position that a candidate can apply for,
format an appropriate email, then incorporate Apex logic into the handleInboundEmail
method to parse received emails.
166
Retrieving Sender Information
2. Determine the format of the email which you would like to process. In this example,
the email will look like this:
167
Chapter 5: Integrating with other Applications
Discussion
The content of an email can be formatted in any number of ways. Ensure that your code can
handle different messages by parsing through the entire body of the email.
See Also
• "Managing Apex Classes" in the Salesforce online help
• "Using the InboundEmail Object" in the Salesforce online help
• "Inbound Email" in the Apex Language Reference at
www.salesforce.com/us/developer/docs/apexcode/index_CSH.htm#apex_classes_email_inbound.htm
• "String Methods" in the Apex Language Reference at
www.salesforce.com/us/developer/docs/apexcode/index_CSH.htm#apex_methods_system_string.htm
Problem
You want to save an attachment received in an email to a record.
Solution
First, verify that the email has either a binary or text attachment. Then, create an attachment
from the file, and associate the attachment with a record.
168
Retrieving Attachments from an Email
Note: For the code sample in this Solution to work, you must have the Recruiting
app metadata in your organization. See The Sample Recruiting App on page 3.
The attachment in this example is a PDF that we will associate with a Job Application as a
resume. The following code snippet should be added to the handIeInboundEmail method
started in Retrieving Sender Information on page 166:
Note: The complete method is listed at the end of Sending an Automatic Email on
page 171. Use the complete sample for testing.
Discussion
Attachments in email can be of a text or binary (for example, .pdf or .doc) type. You can
define a different action to perform depending on the type of file you have received.
See Also
• "InboundEmail.BinaryAttachment Object" in the Apex Language Reference at
www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_email_inbound_binary.htm
• "Using the InboundEmail Object" in the Salesforce online help
• "InboundEmail.TextAttachment Object" in the Apex Language Reference at
www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_email_inbound_text.htm
169
Chapter 5: Integrating with other Applications
Problem
You receive an email from a user for the first time, and want to create a new contact based on
the sender's information.
Solution
Using Apex code, create a new recipient object and populate it.
For this example, we will assume that the sender of the email is a Candidate, and so we want
to create a new object for the data through Apex.
Note: For the code sample in this Solution to work, you must have the Recruiting
app metadata in your organization. See The Sample Recruiting App on page 3.
The following code snippets should be added to the handleInboundEmail method started
in Retrieving Sender Information on page 166.
Candidate__c[] newCandidate = new Candidate__c[0];
Note: The complete method is listed at the end of Sending an Automatic Email on
page 171. Use the complete sample for testing.
See Also
• Retrieving Sender Information on page 166
• "Using the InboundEmail Object" in the Salesforce online help
• "Inbound Email" in the Apex Language Reference at
www.salesforce.com/us/developer/docs/apexcode/index_CSH.htm#apex_classes_email_inbound.htm
170
Sending an Automatic Email
Problem
You want to send an automatic reply to an individual that confirms their email was received.
Solution
The Messaging.sendEmail static method needs to be extended to process outbound email
messaging. Before calling the function, compose an email by defining various fields, such as
the subject and body of the email.
Use the following Apex code within the handleInboundEmail method, started in Retrieving
Sender Information on page 166, to send an automatic response when a candidate's application
is received.
Note: For the code sample in this Solution to work, you must have the Recruiting
app metadata in your organization. See The Sample Recruiting App on page 3.
The following code snippet should be added to the handIeInboundEmail method started
in Retrieving Sender Information on page 166:
public static void send (String emailTo)
{
String[] toAddresses = new String[] {emailTo};
mail.setToAddresses(toAddresses);
mail.setSenderDisplayName('HR Recruiter');
mail.setSubject('Your job application has been received!);
mail.setSaveAsActivity(true);
mail.setPlainTextBody('Thank you for submitting your resume. We will
contact you shortly to set an interview.');
The following Apex code is a complete version of the ProcessApplicant class when
assembling the previous recipes:
global class ProcessApplicant implements Messaging.InboundEmailHandler
{
global Messaging.InboundEmailResult
handleInboundEmail(Messaging.inboundEmail email,
Messaging.InboundEnvelope env)
{
// Create an inboundEmailResult object for returning the result
171
Chapter 5: Integrating with other Applications
try
{
newCandidate.add(new Candidate__c(email__c = emailAddress,
first_name__c = fName,
last_name__c = lName,
phone__c = phoneNumber,
city__c = city));
insert newCandidate;
}
catch (System.DmlException e)
{
System.debug('ERROR: Not able to create candidate: ' + e);
}
insert newJobApplication;
172
Activating Email Services
Name = email.binaryAttachments[i].filename,
Body = email.binaryAttachments[i].body);
insert a;
}
}
// Set the result to true, no need to send an email back to the user
Messaging.SingleEmailMessage mail =
new Messaging.SingleEmailMessage();
mail.setToAddresses(toAddresses);
mail.setSenderDisplayName('HR Recruiter');
mail.setSubject('Your job application has been received');
mail.setSaveAsActivity(true);
mail.setPlainTextBody('Thank you for submitting your resume!
We will contact you shortly to set an interview date.');
See Also
"Outbound Email" in the Apex Language Reference at
http://www.salesforce.com/us/developer/docs/apexcode/index_CSH.htm#apex_classes_email_outbound.htm
Problem
You want to create an email service that runs an Apex class.
Solution
You must activate an email service to automatically process the contents of an Apex class.
173
Chapter 5: Integrating with other Applications
For the ProcessApplicant class you completed in Sending an Automatic Email on page 171,
an email service will allow the handleInboundEmail() and send() functions to properly
execute.
Salesforce then generates an email address unique to the email service. All email sent to this
inbound email address runs the ProcessApplicant class.
Discussion
By themselves, Apex classes implementing Messaging.InboundEmailHandler won't achieve
much unless they are activated. Utilizing them as an email service is the final step to process
received messages.
See Also
• "What are Email Services?" in the Salesforce Online Help
• "Using the InboundEmail Object" in the Salesforce online help
• "Inbound Email" in the Apex Language Reference at
http://www.salesforce.com/us/developer/docs/apexcode/index_CSH.htm#apex_classes_email_inbound.htm
Problem
You want to send an email using a Visualforce email template.
Solution
First, create a Visualforce email template through the email template wizard, then send it to
a contact, user, or lead in your organization.
174
Using Visualforce Email Templates
Note: To create a Visualforce email template, you must have the "Customize
Application" permission enabled.
The following Visualforce markup sends a list of cases associated with an account to a contact,
as well as creates and attaches a PDF containing the same information:
<messaging:emailTemplate recipientType="Contact"
relatedToType="Account"
175
Chapter 5: Integrating with other Applications
<messaging:htmlEmailBody>
<html>
<body>
<style type="text/css">
p {font-family: arial; size: 8pt;}
th {font-size: 11px; font-face: arial;
background: #CCCCCC; border-width: 1; text-align: center }
td {font-size: 11px; font-face: verdana }
table {border: solid #CCCCCC; border-width: 1}
tr {border: solid #CCCCCC; border-width: 1}
</style>
<p>Dear {!recipient.name},</p>
<p>Below is a list of cases related to {!relatedTo.name}.</p>
<table border="0" >
<tr>
<th>Case Number</th><th>Subject</th>
<th>Creator Email</th><th>Status</th>
</tr>
<apex:repeat var="cx" value="{!relatedTo.Cases}">
<tr>
<td><a href =
"https://na1-blitz01.soma.salesforce.com/{!cx.id}">{!cx.CaseNumber}
</a></td>
<td>{!cx.Subject}</td>
<td>{!cx.Contact.email}</td>
<td>{!cx.Status}</td>
</tr>
</apex:repeat>
</table>
<p/>
<center>
<apex:outputLink value="http://www.salesforce.com">
For more detailed information login to Salesforce.com
</apex:outputLink>
</center>
</body>
</html>
</messaging:htmlEmailBody>
176
Using Apex to Update Salesforce Data in the Mobile Application
Discussion
Every Visualforce email template must contain either an htmlEmailBody tag or a
plainTextEmailBody tag. Visualforce email templates cannot be used to send mass email.
See Also
• "Defining Visualforce Pages" in the Salesforce online help
• "Creating Visualforce Email Templates" in the Salesforce online help
Problem
You want to modify related lists of Salesforce records in the mobile application, even when
the records are not available locally on the mobile phone. Optionally, you'll use a Bluetooth
peripheral device to update the data in the records.
Solution
For this recipe, let's assume that your organization sells servers. Your field service representatives
want to update related list information on records from their mobile devices while at customer
sites. For example, if they replace a broken component in a server, they want to be able to enter
the new component's serial number and update the server record. The server will then be
associated with the new component instead of the replaced one.
To accomplish this, we'll create three custom objects and some custom fields. We'll use an
Apex trigger to update the server record when the field service representatives replace a
component.
Before starting this recipe, make sure you meet the following requirements:
• Mobile Licenses: Verify that your Developer Edition organization has mobile licenses.
To find out, simply edit your user record. If the Mobile User checkbox is visible, select it,
then edit your profile and enable the "Manage Mobile Configurations" permission. If the
Mobile User checkbox is already selected, you don't need to do anything else.
177
Chapter 5: Integrating with other Applications
If the Mobile User checkbox isn't available on your user record, you signed up for your
account before mobile licenses were provided by default. Visit Developer Force and click
Getting Started to sign up for a new Developer Edition organization.
• Mobile Devices: Verify that your mobile device will run Force Platform Mobile. See Force
Platform Mobile Supported Devices in the Salesforce online help.
If your mobile device is not supported, you can download and install the BlackBerry
simulator package so you can run the mobile application on a simulator.
First, create a custom object named Server that has a lookup relationship to Account. This
object allows your organization to keep track of the servers housed at each customer's site.
5. In the Custom Fields & Relationships related list, click New and define a second
field with the following attributes:
• Data Type: Text Area
• Field Label: Description
• Field Name: Description
• Field-Level Security: Visible for all profiles
• Add Related List: On all page layouts
Next, create a custom object named Component that has a lookup relationship to Server. This
object represents the various components that can be installed inside a server.
178
Using Apex to Update Salesforce Data in the Mobile Application
5. In the Custom Fields & Relationships related list, click New and define a second
field with the following attributes:
• Data Type: Checkbox
• Field Label: Operational
• Field Name: Operational
• Field-Level Security: Visible for all profiles
• Add Related List: On all page layouts
6. In the Custom Fields & Relationships related list, click New and define a third field
with the following attributes:
• Data Type: Picklist
• Field Label: Type
• Values: Motherboard, RAM, CPU, Network Card, Power Supply
• Field Name: Type
• Field-Level Security: Visible for all profiles
• Add Related List: On all page layouts
7. By default, one of the standard fields for the Component object is Component
Name; however, the field service representatives reference the components by serial
number. We'll change the standard field name to Component Serial Number.
In the Standard Fields related list, click Edit next to Component Name.
8. In the Record Name field, type Component Serial Number.
9. Click Save.
Next, create a custom object named Replacement. This object allows the field service
representatives to enter information about the new component.
1. Click Setup ➤ Create ➤ Objects ➤ New Custom Object.
179
Chapter 5: Integrating with other Applications
5. In the Custom Fields & Relationships related list, click New and define a second
field with the following attributes:
• Data Type: Lookup Relationship
• Related To: Component
• Field Label: New Component
• Field Name: New Component
• Field-Level Security: Hidden from all profiles
• Add Related List: Hidden from all page layouts
6. In the Custom Fields & Relationships related list, click New and define a third field
with the following attributes:
• Data Type: Lookup Relationship
• Related To: Component
• Field Label: Replaced Component
• Field Name: Replaced Component
• Field-Level Security: Hidden from all profiles
• Add Related List: Hidden from all page layouts
In the next two steps, we'll create text versions of the New Component and
Replaced Component lookup fields. This is because Force Platform Mobile
handles lookup fields differently than the Salesforce website. Users can type in
lookup fields on the website, but not in the mobile application. We want the
field representatives to be able to quickly enter the serial number of the new
component, so we'll create text fields to replace the lookup fields.
180
Using Apex to Update Salesforce Data in the Mobile Application
when the record is saved, and then Salesforce validates the user's text entry against
the component records with the Apex trigger.
7. In the Custom Fields & Relationships related list, click New and define a fourth
field with the following attributes:
• Data Type: Text
• Field Label: New Component Serial Number
• Field Name: New Component Serial Number
• Field-Level Security: Visible for all profiles
• Add Related List: On all page layouts
8. In the Custom Fields & Relationships related list, click New and define a fifth field
with the following attributes:
• Data Type: Text
• Field Label: Replaced Component Serial Number
• Field Name: Replaced Component Serial Number
• Field-Level Security: Visible for all profiles
• Add Related List: On all page layouts
Next, create an Apex trigger on the Replacement object so that a server's components are
automatically updated when a field representative creates a replacement record.
181
Chapter 5: Integrating with other Applications
4. Click Save.
182
Using Apex to Update Salesforce Data in the Mobile Application
If this was a real mobile configuration for field representatives, you would probably
also mobilize other objects, like Account and Case. For the recipe, we just need to
mobilize the custom objects we created.
1. On the Salesforce website, create a server record and three related component records
so you have some data to work with in the mobile application.
• Server: IBM BladeCenter S
• Component Serial Number: 100000; Type: CPU
• Component Serial Number: 100001; Type: Motherboard
• Component Serial Number: 100002; Type: Power Supply
2. Create one more component record that is not associated with any server record.
Enter 100003 as the Component Serial Number, and set the Type to CPU.
3. Install the mobile application on your device. For installation instructions, see
Installing Force Platform Mobile in the Salesforce online help. If you're using a
BlackBerry simulator, the mobile application is already installed on the simulator
device; you just need to activate your Salesforce Developer Edition account after
launching Force Platform Mobile for the first time.
4. In the mobile application, select the Replacement tab.
5. Open the menu and select New.
6. In the Replaced Component Serial Number field, type 100000.
7. In the New Component Serial Number field, type 100003.
Tip: Pairing the mobile device with a Bluetooth barcode scanner allows the
field service representative to enter the serial numbers in the replacement
record fields by scanning the barcodes.
Discussion
To make this solution even more effective, implement the Apex trigger and give the field
representatives barcode scanners so that they can quickly scan the serial numbers when replacing
components. Many barcode scanners can operate wirelessly using a Bluetooth connection. Just
pair the barcode scanner with a Bluetooth-enabled mobile device, and you'll be able to use the
scanner for entering data in the mobile application.
183
Chapter 5: Integrating with other Applications
See Also
• For information about extending your Visualforce pages to mobile users, see Retrieving a
User's Location from a GPS-enabled BlackBerry Smartphone on page 184.
• For information about deploying the mobile solution to Salesforce users, see the Force
Platform Mobile Implementation Guide at
http://na1.salesforce.com/help/doc/en/salesforce_mobile_implementation.pdf.
Problem
You want to capture the location where your mobile users enter Salesforce data by retrieving
the GPS coordinates from the BlackBerry smartphone when users save a record.
Solution
Write a Visualforce page that sales representatives can use when logging sales visits. The
Visualforce page contains JavaScript that sends the device's longitude and latitude to Salesforce
when the record is saved. After writing the Visualforce page, we'll create a tab for the page and
add the tab to the mobile application.
Before starting this recipe, make sure you complete the following prerequisites:
• Mobile Licenses: Verify that your Developer Edition organization has mobile licenses.
To find out, simply edit your user record. If the Mobile User checkbox is visible, select it,
then edit your profile and enable the "Manage Mobile Configurations" permission. If the
Mobile User checkbox is already selected, you don't need to do anything else.
If the Mobile User checkbox isn't available on your user record, you signed up for your
account before mobile licenses were provided by default. Visit Developer Force and click
Getting Started to sign up for a new Developer Edition organization.
• Mobile Devices: Verify that your BlackBerry smartphone can use Force Platform Mobile.
See Force Platform Mobile Supported Devices in the Salesforce online help.
• GPS Receiver: Your BlackBerry smartphone must have an internal GPS receiver or an
external Bluetooth GPS receiver; make sure that the receiver is enabled. To find out if your
BlackBerry smartphone's GPS receiver is on, select Options ➤ Advanced ➤ GPS or
Options ➤ Advanced ➤ Location Based Services.
If your device does not meet these requirements, download and install the BlackBerry
simulator package.
184
Retrieving a User's Location from a GPS-enabled BlackBerry Smartphone
First, create a custom object named Sales Visit. This object allows sales representatives to enter
information in Salesforce after making a sales visit.
5. In the Custom Fields & Relationships related list, click New and define a second
field with the following attributes:
• Data Type: Number
• Field Label: Longitude
• Length: 3
• Decimal Places: 10
• Field Name: Longitude
• Field-Level Security: Visible for all profiles
• Add Related List: Select for all page layouts
6. In the Custom Fields & Relationships related list, click New and define a third field
with the following attributes:
• Data Type: Number
• Field Label: Latitude
• Length: 3
• Decimal Places: 10
• Field Name: Latitude
• Field-Level Security: Visible for all profiles
• Add Related List: Select for all page layouts
Create an Apex class that mimics the Sales Visit object but changes the save behavior:
185
Chapter 5: Integrating with other Applications
public visitController() {
visit = new Sales_Visit__c();
}
Normally after saving a record, the record's detail page displays, along with the tabs
and sidebar. The Apex class suppresses all these screen elements—which would
overload the mobile device's small screen—by displaying a blank Sales Visit record
instead.
3. Click Save.
Create a Visualforce page that sends the user's GPS coordinates when the sales visit record is
saved.
186
Retrieving a User's Location from a GPS-enabled BlackBerry Smartphone
5. Click Save.
187
Chapter 5: Integrating with other Applications
1. Install the mobile application on your device. For installation instructions, see
"Installing Force Platform Mobile" in the Salesforce online help. If you're using a
BlackBerry simulator, the mobile application is already installed on the simulator
device; you just need to activate your Salesforce Developer Edition account after
launching Force Platform Mobile for the first time.
If you already completed Using Apex to Update Salesforce Data in the Mobile Application
on page 177, you don't need to reinstall the application. Simply open the mobile
application on your BlackBerry smartphone, open the main menu, and select System
Info. Select Refresh All Data to update the data on your device.
Discussion
Currently, the JavaScript class used in this recipe is only available for BlackBerry smartphones.
See Also
Using Apex to Update Salesforce Data in the Mobile Application on page 177
188
Enabling Single Sign-On with the Force Platform
Problem
You want to validate usernames and passwords for Salesforce against your corporate user
database or another client application rather than having separate user passwords managed by
Salesforce.
Solution
Salesforce offers two ways to use single sign-on:
• Delegated Authentication: You must request that this feature be enabled by salesforce.com.
This recipe explains delegated authentication in more detail.
• Federated Authentication using SAML: For more information, see "Configuring SAML
Settings for Single Sign-On" in the Salesforce online help.
When delegated authentication is enabled, salesforce.com does not validate a user's password.
Instead, salesforce.com makes a Web services call to your organization to establish authentication
credentials for the user.
To enable delegated authentication for your organization, build your delegated authentication
Web service, and then configure your Salesforce organization to enable the Web service.
189
Chapter 5: Integrating with other Applications
namespace samples.sforce.com
{
/// <summary>
/// This is a very basic implemention of an
/// authentication service for illustration purposes.
/// This sample should only be used
/// with a HTTPS Delegated Gateway URL.
/// It simply connects to your Active Directory
/// server using the credentials that are passed in.
/// If there is a bad username/password combination,
/// it throws an exception and returns false;
/// otherwise the credentials are ok
/// and it returns true.
/// Note that DirectoryEntry might not connect to
/// Active Directory until we do something
/// that actually requires it.
/// That's why we read a property from the
/// created DirectoryEntry object.
/// </summary>
public class SimpleAdAuth : System.Web.Services.WebService
{
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute(
"",
RequestNamespace = "urn:authentication.soap.sforce.com",
ResponseElementName = "AuthenticateResult",
ResponseNamespace = "urn:authentication.soap.sforce.com",
Use = System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle =
System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return:
System.Xml.Serialization.XmlElementAttribute("Authenticated")]
190
Enabling Single Sign-On with the Force Platform
Your delegated authentication service needs to accept this request, process it, and
return a true or false response. A sample response is shown below.
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<AuthenticateResponse
xmlns="urn:authentication.soap.sforce.com">
<Authenticated>true</Authenticated>
</AuthenticateResponse>
</soapenv:Body>
</soapenv:Envelope>
2. Add a link to your corporate intranet or other internally-accessible site that takes
the authenticated user’s credentials and passes them using an HTTPS POST to the
Salesforce login page. For security reasons, you should make your service available
by SSL only. This ensures that a password, if it is included, is not sent unencrypted.
You must use an SSL certificate from a trusted provider, such as Verisign or Thawte.
Because Salesforce does not use the password field other than to pass it back to
you, you do not need to send a password in this field. Instead, you could pass another
191
Chapter 5: Integrating with other Applications
When the salesforce.com server passes these credentials back to you in the
Authenticate message, verify them, and the user will gain access to the application.
Finally, modify your user profiles to enable the Is Single Sign-On Enabled user
permission. In Salesforce, click Setup ➤ Manage Users ➤ Profiles to add or edit profiles.
Discussion
The actual implementation of delegated authentication is transparent to users, but involves a
number of steps behind the scenes. When you configure Salesforce for delegated authentication,
you are allowing a delegated authority to control authentication. When a user first logs onto
their network environment, they are initially authenticated by this authority. When the user
attempts to log on to subsequent protected applications, instead of passing a username and
password to the application, the user requests a token from a token generator. (On Windows,
this token request can use the NTLM protocol.) The received token is passed to the application,
which verifies that the token properly identifies the user, and then allows the user access to
the application.
Salesforce can use this method, since the password field is simply used to exchange information
with the client, rather than specifying a particular data type. This flexibility means that Salesforce
can accept a token, which is then used with the delegated authentication authority to verify
the user. If the verification succeeds, the user is logged on to Salesforce. If the verification fails,
192
Enabling Single Sign-On with the Force Platform
the user receives an error. The process flow for Salesforce delegated authentication is shown
in the figure below.
See Also
• How to Implement Single Sign-On with the Force Platform at
wiki.apexdevnet.com/index.php/How_to_Implement_Single_Sign-On_with_Force.com
• "Configuring SAML Settings for Single Sign-On" in the Salesforce online help
• The Single Sign-On Implementation Guide in the Salesforce online help
193
Chapter 6
Integrating Applications with the API and Apex
In this chapter ...
As you become more experienced developing on the
• Setting Up Your Salesforce platform, you'll find that there are some types of applications
Web Services API and integrations that can't be handled by modifying a single
Applications app. For situations like these, you can leverage the powerful,
SOAP-based API to write client applications that are
• Implementing the
created and executed outside of Salesforce.
Query/Query More
Pattern In this chapter, you'll learn about choosing a development
• Batching Records for API language, selecting a WSDL document, and managing API
Calls authentication, sessions, and timeouts. We'll also take a
• Using a Wrapper Class for look at what it takes to build a full-fledged client application
Common API Functions that demonstrates several API best practices.
• Building a Web Portal
with Salesforce Data
• Add and Remove Tags on
a Single Record
• Add and Remove Tags on
Multiple Records
• Updating Tag Definitions
195
Chapter 6: Integrating Applications with the API and Apex
If you're interested in building a Web control or client application, write your code in any
language that supports Web services, including Java, Perl, Python, PHP, Ruby on Rails,
C#.NET, Visual Basic.NET, and Cocoa for Mac OS X. You can find toolkits and code samples
for several Web-services-enabled languages on the Developer Force website at
wiki.apexdevnet.com/index.php/API.
• API Only. This permission specifies that the user can only log in through the API. This
prevents the user from being used for any purpose other than integration scenarios.
• Modify All Data. This permission specifies that the user can view any data stored in the
database and edit any field with the editable flag (some fields, like CreatedDate, do not
have the editable flag set and cannot be edited by any user, regardless of the "Modify All
Data" permission). This permission is also required for any user who wants to upsert
non-unique external IDs through the API.
196
Setting Up Your Salesforce Web Services API Applications
Select a WSDL
A WSDL document is an XML file that describes the format of messages you send and receive
from a Web service. It's the protocol that your development environment's SOAP client uses
to communicate with external services like Salesforce.
Salesforce provides two primary WSDL documents for operating on objects and fields in an
organization, plus three additional WSDL documents for specific features of workflow rules
and the API. Choose the WSDL document you should download and consume based on the
type of application you're going to develop:
Enterprise WSDL
The Enterprise WSDL is a strongly-typed WSDL document for customers
who want to build an integration with their Salesforce organization only,
or for partners who are using tools like Tibco or webMethods to build
integrations that require strong typecasting.
Strong typing means that an object in Salesforce has an equivalent object
in Java, .NET, or whatever environment is accessing the API. This model
generally makes it easier to write code because you don't need to deal with
any underlying XML structures. It's also safer because data and schema
dependencies are resolved at compile time, not at runtime.
Partner WSDL
The Partner WSDL is a loosely-typed WSDL document for customers,
partners, and ISVs who want to build an integration or a Force Platform
AppExchange app that can work across multiple Salesforce organizations.
With this WSDL document, the developer is responsible for marshaling
data in the correct object representation, which typically involves editing
the XML. However, you're also freed from being dependent on any
particular data model or Salesforce organization. Consequently, if you use
the Partner WSDL, you only need to download and consume it once,
regardless of any changes to custom objects or fields.
197
Chapter 6: Integrating Applications with the API and Apex
If you want to view a WSDL document without downloading it, simply click the download
link for the WSDL document you want to view.
Tip: To keep track of the WSDL documents you download, name them with a
date/time stamp.
If you want to generate an Outbound Message WSDL document, click Setup ➤ Create ➤
Workflow & Approvals ➤ Outbound Messagaes. Select the name of the outbound message
and then click Click for WSDL. This file is bound to the outbound message and contains the
instructions about how to reach the endpoint service and what data is sent to it.
198
Setting Up Your Salesforce Web Services API Applications
The Partner WSDL is based on a generic SObject, which represents a Salesforce record such
as a particular account or contact. Every SObject has the following properties:
FieldsToNull string[] An array of one or more field names whose value you
want to explicitly set to null. This array is used only
with the update() or upsert() calls.
Note that you can only specify fields that you can update
and that are nillable. For example, specifying an ID
field or required field results in a runtime error.
The Partner WSDL provides methods that allow you to work with these properties so that
you can perform the same tasks with the Partner WSDL as you can with the Enterprise WSDL.
For example, the following Java code creates a job application record using the Enterprise
WSDL:
"If You Use the Partner WSDL" contributed by Simon Fell, Principal Member of the Technical
Staff at salesforce.com
199
Chapter 6: Integrating Applications with the API and Apex
jobApp.setCandidate__c(new ID(candidateId));
jobApp.setPosition__c(new ID(positionId));
jobApp.setStatus__c("New");
SaveResult [] sr = binding.create(new SObject[] {jobApp});
if(!sr[0].isSuccess())
throw new SaveException(sr[0]);
jobApp.setId(sr[0].getId());
return jobApp;
}
The same createJobApp() method can also be written in Java with the Partner WSDL:
// Position id
field[1] = util.createNewXmlElement("Position__c", positionId);
// Status
field[2] = util.createNewXmlElement("Status__c", "New");
jobApp.set_any(fields);
jobApp.setType("Job_Application__c");
SaveResult [] sr = binding.update(new SObject[] {jobApp});
if(!sr[0].isSuccess())
throw new SaveException(sr[0]);
jobApp.setId(sr[0].getId());
return jobApp;
}
The following VB.NET code creates a position record using the Enterprise WSDL:
200
Setting Up Your Salesforce Web Services API Applications
e2.InnerText = "Open"
p.Any = new XmlElement() {e1,e2}
binding.update(New sObject() {p})
Note: In these examples, notice that Java and .NET use different elements to represent
field name/value pairs. For example, given the following name/value pair:
<City__c>Chicago</City__c>
Similar to the way the login page works in the Salesforce user interface, the login() call takes
a username and password and executes a login sequence on https://www.salesforce.com/.
If the login is successful, the login() call returns a session ID and URL. The session ID
represents the user's authentication token and the URL points to the host that contains data
for the user's organization.
Note: For performance and reliability, the platform runs on multiple instances (for
example, na1.salesforce.com, na2.salesforce.com, and so on), but data for any single
organization is always consolidated on a single instance. As long as you use the URL
"Log In to and Out of the API" contributed by Simon Fell, Principal Member of the Technical
Staff at salesforce.com
201
Chapter 6: Integrating Applications with the API and Apex
that is returned from the login() call, you should never need to know the actual
instance that hosts an organization's data.
Once you've obtained a session ID and server URL, you'll generally include the session ID in
every API call, and you'll direct your client to make the API request to the host that you
obtained.
Tip: It's not necessary to use login() when writing an s-control that executes within
the Salesforce user interface because the user accessing the s-control has already logged
in and acquired a session ID.
To log in, acquire a Salesforce session ID and the appropriate host for your organization by
using the login() call.
For example, the following Java code from the wrapper class described in Using a Wrapper Class
for Common API Functions on page 210:
• Logs in to Salesforce
• Sets the login time
• Resets the URL for the SOAP binding stub to the returned server URL
• Creates a new session header for the binding class variable
• Updates the wrapper class' sessionID and serverURL variables
/**
* This method is used to log in to salesforce and set the
* private class variables for the wrapper, including the
* session ID.
*/
public void login() throws UnexpectedErrorFault, InvalidIdFault,
LoginFault, RemoteException,
ServiceException {
resetBindingStub();
LoginResult loginResult = binding.login(username, password);
this.nextLoginTime = System.currentTimeMillis() +
(this.sessionlength * 60000);
this.binding._setProperty(SoapBindingStub.
202
Setting Up Your Salesforce Web Services API Applications
ENDPOINT_ADDRESS_PROPERTY,
loginResult.getServerUrl());
this.sessionId = loginResult.getSessionId();
this.serverUrl = loginResult.getServerUrl();
"SessionHeader", sh);
}
This VB .NET code performs the same logic as for the VB.NET version of the wrapper class
(see Using a Wrapper Class for Common API Functions on page 210):
To log out of the session you created, issue the logout() call.
Java:
/**
* This method is used to log out of salesforce
*/
public void logout() {
try {
binding.logout();
}
catch (Exception e) {
System.out.println("Unexpected error:\n\n" + e.getMessage());
}
}
VB.NET:
203
Chapter 6: Integrating Applications with the API and Apex
Me._binding.logout()
End Sub
Manage Sessions
An integration may last longer than the session timeout value specified for an organization,
but logging in to Salesforce every time you need to make an API call is inefficient. To manage
sessions, use the information in this section.
The session timeout value is the amount of time a single session ID remains valid before
expiring. While a session is always valid for a user while he or she is working in the Web
interface, sessions instantiated via the API expire after the duration of the session timeout,
regardless of how many transactions are still taking place.
You can manage sessions by writing a method that checks to see whether your session ID is
about to expire by comparing your last login time with the current session length. When this
method returns true, log in again.
For example, the following Java code from the wrapper class discussed in Using a Wrapper Class
for Common API Functions on page 210 implements a loginRequired() method:
/**
* This method returns true if a login to Salesforce is
* necessary, otherwise false. It should be used to check the
* session length before performing any API calls.
*/
private boolean loginRequired() {
if (sessionId == null || sessionId.length() == 0)
return true;
return !isConnected();
}
/**
* This method checks whether the session is active or not
* @return boolean
*/
public boolean isConnected() {
return System.currentTimeMillis() < nextLoginTime;
}
"Manage Sessions" contributed by Simon Fell, Principal Member of the Technical Staff at
salesforce.com
204
Setting Up Your Salesforce Web Services API Applications
End Function
Tip: Be sure that the value you use for session length is no more than the configured
session timeout value. Because the session timeout value for an organization is not
accessible through the API, it's a good idea to build applications that assume a
thirty-minute session timeout so that administrators don't inadvertently break your
integrations.
This example is very simple. Another, more robust option is to catch the session expiration
remove exception (Exception Code - INVALID_SESSION_ID) and only then log in again.
This ensures that you only log in when absolutely necessary and that you'll get a new session
ID if your current session ever becomes invalid. This method is usually coupled with
implementing retry logic.
Note:
• Make sure you update any integration code so that it uses the new timeout value!
Otherwise your integrations might break.
• Changing the session timeout value affects all users equally in an organization.
205
Chapter 6: Integrating Applications with the API and Apex
Problem
You need to issue queries that return more than 2000 records, but the query() call can only
return up to 2000 at a time.
Solution
Use queryMore() to retrieve any additional records in batches of up to 2000 at a time. The
queryMore() call takes a single queryLocator parameter that specifies the index of the last
result record that was returned. This queryLocator is created and returned by the previous
query() or queryMore() call.
When the query() or queryMore() calls return a result with the isDone flag set to true,
there are no more records to process.
For example, the following Java code implements the query()/queryMore() pattern when
querying leads:
"Implementing the Query/Query More Pattern" contributed by Simon Fell, Principal Member of
the Technical Staff at salesforce.com, and Nick Tran, Developer Relations Senior Manager for
salesforce.com
206
Batching Records for API Calls
The query()/queryMore() batch size defaults to 500 records, but can be as small as 200 or
as large as 2000. To change the batch size, use the QueryOptions header.
Note:
• If you use query()/queryMore() during a long-running integration scenario
where you need to log in again to get new session IDs, the queryLocator cursor
remains valid after you log in, as long as you get the next batch of records within
fifteen minutes of idle time.
• Only ten queryLocator cursors can be active for an organization at any one time.
See Also
• Manage Sessions on page 204
• Using a Wrapper Class for Common API Functions on page 210
• Batching Records for API Calls on page 207
Problem
You want to create, update, or delete records in the Salesforce database, but you have more
than 200 records you want to process, which exceeds the maximum allowed per call.
Solution
Write a method that batches the records into multiple API calls.
For example, the following Java code from the wrapper class described in Using a Wrapper Class
for Common API Functions on page 210 implements a create() method that takes an array of
SObjects and a batch size as parameters. Any method that calls create() can pass in any
number of records and dynamically vary the batch size to improve performance:
/**
* This method creates an array of sObjects with a specified
* batchSize.
* @param records
* @param batchSize
* @return SaveResult[]
*/
public SaveResult[] create(SObject[] records, int batchSize)
Code for "Batching Records for API Calls" contributed by Simon Fell, Principal Member of the
Technical Staff at salesforce.com
207
Chapter 6: Integrating Applications with the API and Apex
208
Batching Records for API Calls
As sforce.SaveResult()
Return batch(records, batchSize, New CreateBatcher)
End Function
pos += sr.Length
End While
batch = saveResults
End Function
209
Chapter 6: Integrating Applications with the API and Apex
perform = Nothing
End Function
End Class
See Also
• Manage Sessions on page 204
• Using a Wrapper Class for Common API Functions on page 210
• Log In to and Out of the API on page 201
Problem
You find yourself writing similar sections of code wherever you need to make calls to the API
in a client application.
Solution
Use an API wrapper class to abstract common functions whenever you write client applications
and integrations. A wrapper class makes your integration more straightforward to develop and
maintain, keeps the logic necessary to make API calls in one place, and affords easy reuse across
all components that require API access.
"Using a Wrapper Class for Common API Functions" contributed by Simon Fell, Principal Member
of the Technical Staff at salesforce.com
210
Using a Wrapper Class for Common API Functions
Wrapper classes typically include methods for the following types of actions:
• Logging in
• Managing sessions
• Querying with the query()/queryMore() pattern
• Batching records for create, update, delete, and so on
For example, the following Java code is a complete implementation of the wrapper class used
in Building a Web Portal with Salesforce Data on page 223:
package com.sforce.client;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;
import org.apache.axis.transport.http.HTTPConstants;
import com.sforce.soap.partner.AssignmentRuleHeader;
import com.sforce.soap.partner.LoginResult;
import com.sforce.soap.partner.QueryOptions;
import com.sforce.soap.partner.QueryResult;
import com.sforce.soap.partner.SaveResult;
import com.sforce.soap.partner.SessionHeader;
import com.sforce.soap.partner.SforceServiceLocator;
import com.sforce.soap.partner.SoapBindingStub;
import com.sforce.soap.partner.fault.InvalidIdFault;
import com.sforce.soap.partner.fault.InvalidSObjectFault;
import com.sforce.soap.partner.fault.LoginFault;
import com.sforce.soap.partner.fault.UnexpectedErrorFault;
import com.sforce.soap.partner.sobject.SObject;
/**
211
Chapter 6: Integrating Applications with the API and Apex
/**
* These methods get and set the private class variables
*/
public String getUsername() {
return this.username;
}
212
Using a Wrapper Class for Common API Functions
/**
* This method is used to log in to salesforce and set the
* private class variables for the wrapper, including the
* session ID.
*/
public void login() throws UnexpectedErrorFault, InvalidIdFault,
LoginFault, RemoteException,
ServiceException {
resetBindingStub();
LoginResult loginResult = binding.login(username, password);
this.nextLoginTime = System.currentTimeMillis() +
(this.sessionlength * 60000);
this.binding._setProperty(SoapBindingStub.
ENDPOINT_ADDRESS_PROPERTY,
loginResult.getServerUrl());
this.sessionId = loginResult.getSessionId();
this.serverUrl = loginResult.getServerUrl();
/**
* This method is used to log in with an existing sessionId
* @param String sid sessionId
213
Chapter 6: Integrating Applications with the API and Apex
/**
* This method checks whether the session is active or not
* @return boolean
*/
public boolean isConnected() {
return System.currentTimeMillis() < nextLoginTime;
}
/**
* This method returns true if a login to Salesforce is
* necessary, otherwise false. It should be used to check the
* session length before performing any API calls.
*/
private boolean loginRequired() {
if (sessionId == null || sessionId.length() == 0)
return true;
214
Using a Wrapper Class for Common API Functions
return !isConnected();
}
/**
* This method queries the database and returns the results.
* @param String strSOQLStmt
* @return SObject[]
*/
public QueryResult executeQuery(String strSOQLStmt,
Integer queryBatchSize)
throws UnexpectedErrorFault, InvalidIdFault, LoginFault,
RemoteException, ServiceException {
checkLogin();
setBatchSizeHeader(queryBatchSize ==
null ? querySize : queryBatchSize);
return binding.query(strSOQLStmt);
}
/**
* This method sets the assignment rule header.
* @param ruleId
*/
public void setAssignmentRuleHeaderId(String ruleId) {
setAssignmentRuleHeader(ruleId, false);
}
/**
* This method sets the assignment rule header with a
* default ruleId.
215
Chapter 6: Integrating Applications with the API and Apex
* @param ruleId
*/
public void setAssignmentRuleHeaderToDefault
(boolean runDefaultRule) {
setAssignmentRuleHeader(null, runDefaultRule);
}
/**
* This method creates an array of sObjects with a specified
* batchSize.
* @param records
* @param batchSize
* @return SaveResult[]
*/
public SaveResult[] create(SObject[] records, int batchSize)
throws InvalidSObjectFault, UnexpectedErrorFault,
InvalidIdFault, RemoteException,
ServiceException {
if (batchSize > 200 || batchSize < 1)
throw new IllegalArgumentException(
"batchSize must be between 1 and 200");
return batch(records, batchSize, new CreateBatcher());
}
216
Using a Wrapper Class for Common API Functions
/**
* This method updates an array of sObjects with a specified
* batchSize.
* @param records
* @param batchSize
* @return SaveResult[]
*/
public SaveResult[] update(SObject[] records)
throws UnexpectedErrorFault, InvalidIdFault, LoginFault,
RemoteException, ServiceException {
return update(records, 200);
}
217
Chapter 6: Integrating Applications with the API and Apex
This code implements the VB.NET version of the wrapper class used in Building a Web Portal
with Salesforce Data on page 223:
Imports Microsoft.VisualBasic
Imports System
Imports System.Collections
Imports sforce
218
Using a Wrapper Class for Common API Functions
End Get
'Allows calling class to set value
Set(ByVal Value As String)
Me._username = Value
End Set
End Property
219
Chapter 6: Integrating Applications with the API and Apex
End Set
End Property
220
Using a Wrapper Class for Common API Functions
_binding.AssignmentRuleHeaderValue.useDefaultRule =
runDefaultRule
End Sub
As sforce.SaveResult()
Return batch(records, batchSize, New CreateBatcher)
End Function
221
Chapter 6: Integrating Applications with the API and Apex
As sforce.SaveResult()
Return batch(records, batchSize, New UpdateBatcher)
End Function
pos += sr.Length
End While
batch = saveResults
End Function
222
Building a Web Portal with Salesforce Data
End Class
See Also
• Building a Web Portal with Salesforce Data on page 223
• Log In to and Out of the API on page 201
• Manage Sessions on page 204
• Implementing the Query/Query More Pattern on page 206
• Batching Records for API Calls on page 207
Problem
You want to build a Web portal for the Recruiting app that allows visitors to apply online for
open positions. The portal needs to include the following Web pages:
• A list view of all currently open positions, with data from the position records that are
stored in Salesforce
• Detail views of all currently open positions, also with data from the position records that
are stored in Salesforce
• An online application form that allows a visitor to apply for an open position. When the
user clicks Submit, the data is sent back to Salesforce as a new job application and candidate
record.
Most importantly, your Web portal visitors shouldn't have to log in to view the open positions
in your organization.
Code for "Building a Web Portal with Salesforce Data" contributed by Sarah Whitlock, Senior
Program Manager for Education Services former at salesforce.com, and Simon Fell, Principal
Member of the Technical Staff at salesforce.com
223
Chapter 6: Integrating Applications with the API and Apex
Note: This Web portal is part of the Application Laboratory class offered by
salesforce.com Training & Certification. For more information, see
www.salesforce.com/training.
224
Building a Web Portal with Salesforce Data
Solution
Write a client application that runs on an external server and uses the Force Platform API to
access Salesforce data.
Note: Because there's a lot of code involved with this solution, this recipe discusses
how such a client can be designed, and some of the features that can be implemented.
To download the complete Java, C#.NET, or VB.NET code that implements this
client application, visit
wiki.apexdevnet.com/index.php/Force_Platform_Cookbook.
The following diagram shows the key components of such an application. While there can be
some overlap, each component represents a different aspect of the MVC
(Model-View-Controller) design paradigm:
225
Chapter 6: Integrating Applications with the API and Apex
Model
The API wrapper class and the WSDL-compiled proxy classes provide
non-application-specific access to the data in Salesforce. See Using a
Wrapper Class for Common API Functions on page 210 for the wrapper class
used to implement the Web portal application.
View
The JSP or ASPX pages contain the user interface of the application,
including how the data is displayed for and captured from the user.
Controller
The delegator, utility, and business logic classes define the
application-specific logic, including the logic that controls how captured
data is returned to Salesforce as new or updated records.
226
Building a Web Portal with Salesforce Data
Of particular note is the delegator class that the Web portal application uses to provide common,
reusable code for creating and updating the key objects related to the application, such as Job
Application and Candidate. Unlike the API wrapper class, which can be reused by many
different client applications, the delegator is application-specific, providing an additional layer
of abstraction between the API and the logic required to display the application's pages.
For example, the following Java-based delegator method provides the logic for creating a job
application record. Based on the Partner WSDL, it prepares a single record and passes it to
the wrapper class for creation via the API:
try {
MessageElement[] fields = new MessageElement[3];
MessageElement field;
//Candidate id
field = util.createNewXmlElement("Candidate__c",
candidateId);
fields[0] = field;
//Positionid
field = util.createNewXmlElement("Position__c",
positionId);
fields[1] = field;
//Status
field = util.createNewXmlElement("Status__c",
"New");
fields[2] = field;
application.set_any(fields);
application.setType("Job_Application__c");
application = createOneRecord(application);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return application;
}
227
Chapter 6: Integrating Applications with the API and Apex
' Candidate id
field = util.createNewXmlElement("Candidate__c",
candidateId)
fields(0) = field
' Position id
field = util.createNewXmlElement("Position__c",
positionId)
fields(1) = field
' Status
field = util.createNewXmlElement("Status__c",
"New")
fields(2) = field
application.Any = fields
application.type = "Job_Application__c"
application = createOneRecord(application)
Return application
End Function
Discussion
The code that implements this Web portal client application also uses a configuration file and
SOAP message compression, two best practices for client application development:
• Using a configuration file to control dynamic aspects of a client application is highly
recommended because it reduces code maintenance time. It can include properties such as
the API URL, username, password, and any SOQL or SOSL queries that drive business
logic. For example, by storing the URL of the targeted Salesforce host in a configuration
file, changing an integration target from sandbox to production only requires a simple
configuration file edit.
The Java-based solution uses a configuration file named config.properties, while the
VB.NET and C#.NET solutions use configuration files named web.config.
• SOAP messages generated by both an API client and the API service can become very
large, especially when they include large clobs of data, such as the resume attachment in
the Web portal client application. To avoid lengthy transmission times across the Internet,
you can configure your SOAP binding to use GZIP compression to reduce the size of
SOAP messages by up to 90%. When the API server receives a compressed message, it
decompresses the message, processes it, and then recompresses the response before returning
it.
The Java-based solution uses the following classes to compress and decompress SOAP
messages:
◊ GZipWebRequest.java
228
Add and Remove Tags on a Single Record
◊ GZipWebResponse.java
◊ GZIP2WayRequestStream.java
◊ GZIP2WayRequestWrapper.java
◊ GZIP2WayResponseStream.java
◊ GZIP2WayResponseWrapper.java
See Also
• Log In to and Out of the API on page 201
• Manage Sessions on page 204
• Implementing the Query/Query More Pattern on page 206
• Batching Records for API Calls on page 207
Problem
You want to remove a public tag that is no longer applicable and add a new public tag for an
existing record.
Solution
To add or remove a tag on a single record, you should first query the record to determine which
tags are already present, before continuing with the create() and delete() operations.
1. To see the tags on a single contact, for example a contact named John Smith, execute
the following in the AJAX Toolkit or your own client application:
var johnSmithTags = sforce.connection.query("SELECT Name, Id,
ItemId
FROM ContactTag WHERE Item.LastName = \'Smith\' AND
Item.FirstName = \'John\'");
229
Chapter 6: Integrating Applications with the API and Apex
• Northwest
• Staff
John Smith has been promoted from Staff to Senior Staff, a tag that does not yet
exist.
2. To create the new Senior Staff tag, execute the following in the AJAX Toolkit or
your own client application:
var SeniorStaffTag = new sforce.SObject('ContactTag');
SeniorStaffTag.ItemId = johnSmithResults.records[0].Id;
SeniorStaffTag.Name = "Senior Staff";
SeniorStaffTag.Type = "Public";
sforce.connection.create([SeniorStaffTag]);
3. Run the query in the first step again. johnSmithTags contains the following tag
names:
• Northwest
• Senior Staff
• Staff
4. The Staff position is eliminated. To remove the Staff tag, delete its ID:
var staffID = sforce.connection.query("SELECT Id FROM ContactTag
5. Run the query in the first step again. johnSmithTags contains the following tag
names:
• Northwest
• Senior Staff
Discussion
Query to ensure that records have been tagged appropriately.
The API enforces the same limits as the Salesforce user interface on the number of tags that
you can create.
230
Add and Remove Tags on Multiple Records
See Also
• "Tagging Limits" in the Salesforce Online Help
• "TagDefinition" in the Force Platform Web Services API Developer's Guide at
http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_objects_tagdefinition.htm
• "create()" in the Force Platform Web Services API Developer's Guide at
http://www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_create.htm
• "delete()" in the Force Platform Web Services API Developer's Guide at
http://www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_delete.htm
• The AJAX Toolkit Developer's Guide at http://www.salesforce.com/
us/developer/docs/ajax/index.htm
Problem
You want to remove public tags that are no longer applicable to multiple records of the same
object type and replace them with a different tag.
Solution
To work with multiple records, loop through all records with a particular tag, collect their
ItemIds, and edit them on an individual basis.
Suppose that all Northwest and Southwest tags need to be consolidated to a single West Coast
tag. To remove the tags and replace them:
1. Store the accounts that contain the tags you want to delete. You can execute the
following in the AJAX Toolkit or your own client application:
var westCoastAccounts = sforce.connection.query("SELECT ItemId,
Id
FROM AccountTag WHERE Name = 'Northwest' OR Name =
'Southwest'");
2. Create the new West Coast tag. Add the ItemIds by looping through the records:
var WestCoastTagArray = new Array();
for (var i = 0; i < westCoastAccounts.size; i++)
{
WestCoastTagArray[i] = new sforce.SObject('AccountTag');
WestCoastTagArray[i].Name = "West Coast";
WestCoastTagArray[i].Type = "Public";
WestCoastTagArray[i].ItemId =
231
Chapter 6: Integrating Applications with the API and Apex
westCoastAccounts.records[i].ItemId;
}
sforce.connection.create(WestCoastTagArray);
Discussion
Make as few calls to the database as possible for the best performance. It is efficient to create
a single array, populate it with a for loop, and call a single database operation, such as
create() or delete(), on that array.
The API enforces the same limits as the Salesforce user interface on the number of tags that
you can create.
See Also
• "TagDefinition" in the Force Platform Web Services API Developer's Guide at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_objects_tagdefinition.htm
• "create()" in the Force Platform Web Services API Developer's Guide at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_create.htm
• "delete()" in the Force Platform Web Services API Developer's Guide at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_delete.htm
Problem
You want to correct some public tags that have misspellings in them and remove some that
are no longer useful in your application.
232
Updating Tag Definitions
Solution
Run a query to determine the ID of the incorrect tag, then rename it. For example, suppose
you see that a user has created a tag called WC. You want to retrieve the ID of this tag to see
which records it is applied to. You canexecute the following in the AJAX Toolkit or your own
client application:
2. The name WC should be West Coast. Since this change affects multiple record
types, create a new TagDefinition record with the correct value.
var updateTD = new sforce.SObject('TagDefinition');
updateTD.Id = IDToUpdate.records.Id;
IDToUpdate.records.Name = "West Coast";
3. updateTD is used to replace the previous TagDefinition record. The final step
is to call update() using the corrected record.
sforce.connection.update([updateTD]);
Since we essentially overwrote the ID, every record previously tagged with WC will
now be tagged as West Coast.
Discussion
Operating on TagDefinition records does not take into consideration the types of any child
tags. Ensure that the action you want to perform is appropriate for all types of tags. For instance,
an AccountTag named WC and an ContactTag named WC will both be changed to West
Coast. For information on changing tags on multiple records, see Add and Remove Tags on
Multiple Records on page 231.
See Also
• "TagDefinition" in the Force Platform Web Services API Developer's Guide at
www.salesforce.com/us/developer/docs/api/Content/sforce_api_objects_tagdefinition.htm
• "update()" in the Force Platform Web Services API Developer's Guide at
www.salesforce.com/us/developer/docs/api/index_CSH.htm#sforce_api_calls_update.htm
233
Glossary
AJAX Toolkit
A JavaScript wrapper around the API that allows you to execute any API call and
access any object you have permission to view from within JavaScript code.
AJAX Tools
A Force Platform AppExchange app that includes a collection of Web-based
utilities for developers working with the AJAX Toolkit, s-controls, or Apex.
Anonymous block, Apex
An Apex script that does not get stored in the metadata, but that can be compiled
and executed through the use of the ExecuteAnonymousResult() API call,
or the equivalent in the AJAX toolkit.
Apex
A procedural scripting language that allows developers to execute flow and
transaction control statements on the Force Platform server in conjunction with
calls to the API. Using syntax that looks like Java and acts like database stored
procedures, Apex allows developers to add business logic to most system events,
including button clicks, related record updates, and custom s-control display.
Apex log
A debug console that displays the debug log for any Apex in your organization
that executes as the result of a trigger while the console is open. The debug console
also includes a text area at the bottom of the window that allows you to enter and
execute anonymous statements.
App
A collection of components such as tabs, reports, dashboards, and custom s-controls
that address a specific business need. Short for "application."
Application programming interface (API)
The interface that a computer system, library, or application provides in order to
allow other computer programs to request services from it and exchange data
between them.
235
Glossary
Approval process
An automated process your organization can use to approve records on the
platform. An approval process specifies the steps necessary for a record to be
approved and who must approve it at each step. Approval processes also specify
the actions to take when a record is approved, rejected, or first submitted for
approval.
Auto number
A custom field type that automatically adds a unique sequential number to each
record.
Cascading style sheets
Files that contain all of the information relevant to color, font, borders, and images
that are displayed in a user interface.
Child relationship
A relationship that has been defined on an SObject that references a selected
SObject as the "one" side of a one-to-many relationship. For example, if you
expand the Child Relationships node under the Account object, contacts,
opportunities, and tasks are included in this list.
Class, Apex
A template or blueprint from which Apex objects are created. Classes consist of
other classes, user-defined methods, variables, exception types, and static
initialization code. In most cases, Apex classes are modeled on their counterparts
in Java and can be quickly understood by those who are familiar with them.
Client app
An app that runs outside the Salesforce user interface and uses only the
API—typically running on a desktop or mobile device. These apps treat the
platform as a data source, using the development model of whatever tool and
platform for which they are designed. See also Composite app on page 236 and
Native app on page 241.
Component library, Visualforce page
The list of tags and attributes that can be used in a Visualforce page.
Composite app
An app that combines native platform functionality with one or more external
Web services, such as Yahoo! Maps. Composite apps allow for more flexibility
and integration with other services, but may require running and managing external
code. See also Client app on page 236 and Native app on page 241.
Controller, Visualforce page
An Apex class that provides a Visualforce page with the data and business logic
it needs to run. Visualforce pages can use the standard controllers that come by
default with every standard or custom object, or they can define custom controllers.
Controlling field
Any standard or custom picklist or checkbox field whose values control the available
values in one or more corresponding dependent fields. See also Dependent field on
page 237.
Custom field
Fields that can be added to customize an object for your organization’s needs.
236
Glossary
Custom link
A custom URL defined by an administrator to integrate your data with external
websites and back-office systems.
Custom object
An entity that you build to store information that's unique to your app. See also
Object on page 241 and Standard object on page 245.
Dashboard
A graphical representation of data from up to 20 summary or matrix reports
arranged in a two- or three-column layout. Every user can select a favorite
dashboard to display on his or her Home tab.
Database
An organized collection of information.The underlying architecture of the platform
includes a database where your data is stored.
Database table
A list of information, presented with rows and columns, about the person, thing,
or concept you want to track. See also Object on page 241.
Date literal
A keyword in a SOQL or SOSL query that represents a relative range of time
such as last month or next year.
Dependent field
Any custom picklist or multi-select picklist field that displays available values
based on the value selected in its corresponding controlling field. See also
Controlling field on page 236.
Developer Edition
A free Salesforce edition that allows you to get hands-on experience with all aspects
of the platform in an environment designed for development. Developer Edition
accounts are available at developer.force.com.
Developer Force
The Developer Force website at developer.force.com provides a full range of
resources for platform developers, including sample code, toolkits, an online
developer community, and the test environments necessary for building apps.
DML statement
An Apex statement that inserts, updates, or deletes records from the Force Platform
database.
Email template
A built-in feature that enables you to create form emails that communicate a
standard message, such as a welcome letter to new employees or an
acknowledgement that a customer service request has been received.
Enterprise Edition
A Salesforce edition designed to meet the needs of larger, more complex businesses.
In addition to all of the functionality available in Professional Edition, Enterprise
Edition organizations get advanced customization and administration tools that
can support large-scale deployments.
237
Glossary
Enterprise WSDL
A strongly-typed WSDL for customers who want to build an integration with
their Salesforce organization only, or for partners who are using tools like Tibco
or webMethods to build integrations that require strong typecasting. The downside
of the Enterprise WSDL is that it only works with the schema of a single Salesforce
organization because it's bound to all of the unique objects and fields that exist in
that organization's data model. See also Partner WSDL on page 242.
Entity relationship diagram (ERD)
A data modeling tool that helps you organize your data into entities (or objects,
as they are called in the Force Platform) and define the relationships between
them.
Field
A part of an object that holds a specific piece of information, such as a text or
currency value.
Field dependency
A filter that allows you to change the contents of a picklist based on the value of
another field.
Field-level security
Settings that determine whether fields are hidden, visible, read only, or editable
for users based on their profiles.
Flex Toolkit for the Force Platform
An Adobe® FlexTM library that allows you to access Salesforce data from within
a Flex 2 application.
Force Platform
A platform for building cloud computing applications from salesforce.com. The
Force Platform combines a powerful user interface, operating system, and database
to allow you to customize and deploy cloud computing applications for your entire
enterprise.
Force Platform API
A Web services-based application programming interface that provides access to
your Salesforce organization's information.
Force Platform API WSDL
A WSDL for developers who want to run or compile Apex scripts in another
environment, build a new Apex IDE, or create an integration or similar application.
Force Platform app menu
A menu that enables users to switch between customizable applications (or "apps")
with a single click. The Force Platform app menu displays at the top of every page
in the Salesforce user interface.
Force Platform AppExchange
A Web directory where hundreds of AppExchange apps are available to Salesforce
customers to review, demo, comment upon, and/or install. Developers can submit
their apps for listing on AppExchange if they wish to share them with the
community.
238
Glossary
239
Glossary
HTTP debugger
An application that can be used to identify and inspect SOAP requests that are
sent from the AJAX Toolkit. They behave as proxy servers running on your local
machine and allow you to inspect and author individual requests.
ID
A unique 15- or 18-character alphanumeric string that identifies a single record
in Salesforce.
Inline s-control
An s-control that displays within a record detail page or dashboard, rather than
on its own page.
Instance, Salesforce Server
A server that hosts an organization's Salesforce data (for example,
na1.salesforce.com, na2.salesforce.com, and so on). The platform
runs on multiple instances, but data for any single organization is always
consolidated on a single instance. As long as you use the URL that is returned
from the API login() call, you should never need to know the actual instance
that hosts an organization's data.
Integration user
A Salesforce user defined solely for client apps or integrations.
Junction object
A custom object that enables a many-to-many relationship between two other
objects.
Layout
See Page layout on page 242.
License Management Application (LMA)
A free Force Platform AppExchange app that allows you to track sales leads and
accounts for every user who downloads a managed package of yours from
AppExchange. See also License Management Organization (LMO) on page 240.
License Management Organization (LMO)
The organization in which you've installed the License Management Application
(LMA). See also Managed package on page 240.
Lookup relationship
A relationship between two objects that allows you to associate records with each
other. On one side of the relationship, a lookup field allows users to click a lookup
icon and select another record from a list. On the associated record, you can then
display a related list to show all of the records that have been linked to it.
Managed package
A collection of application components that are posted as a unit on Force Platform
AppExchange, and that are associated with a namespace and a License
Management Organization. A package must be managed for it to be published
publicly on AppExchange, and for it to support upgrades. See also Force Platform
AppExchange package on page 239.
240
Glossary
Manual sharing
Record-level access rule that allows record owners to give read and edit permissions
to other users who might not have access to the record any other way. See also
Record-level security on page 243.
Merge field
A field you can place in an email template, custom link, s-control, or
formula to incorporate values from a record. For example, Dear
{!Contact.FirstName}, uses a contact merge field to obtain the value
of a contact record's First Name field to address an email recipient by
his or her first name.
Metadata-driven development
An app development model that allows apps to be defined as declarative
“blueprints,” with no code required. Apps built on the platform—their data models,
objects, forms, workflows, and more—are defined by metadata.
Metadata WSDL
A WSDL for users who want to use the API metadata calls.
Multitenancy
An application model where all users and apps share a single, common
infrastructure and code base.
MVC (Model-View-Controller)
A design paradigm that deconstructs applications into components that represent
data (the model), ways of displaying that data in a user interface (the view), and
ways of manipulating that data with business logic (the controller).
Namespace
A one- to 15-character alphanumeric identifier that distinguishes your package
and its contents from packages of other developers on Force Platform
AppExchange, similar to a domain name. Salesforce automatically prepends your
namespace prefix, followed by two underscores ("__"), to all unique component
names in your Salesforce organization.
Native app
A type of app that is built exclusively via metadata configuration and without
coding. Native apps run entirely on the platform without need for external services
or infrastructure. See also Client app on page 236 and Composite app on page 236
Object
In Force Platform terms, an object is similar to a database table—a list of
information, presented with rows and columns, about the person, thing, or concept
you want to track. Each object automatically has built-in features like a user
interface, a security and sharing model, workflow processes, and much more.
Object-level security
Settings that allow an administrator to hide whole tabs and objects from a user,
so that they don't even know that type of data exists. On the platform, you set
object-level access rules with object permissions on user profiles. See also Field-level
security on page 238 and Record-level security on page 243.
241
Glossary
onClick JavaScript
JavaScript code that executes when a button or link is clicked.
One-to-many relationship
A relationship in which a single object is related to many other objects. For
example, each Candidate may have one or more related Job Applications.
Organization-wide defaults
Settings that allow you to specify the baseline level of data access that a user has
in your organization. For example, you can make it so that any user can see any
record of a particular object that's enabled in their user profile, but that they'll
need extra permissions to actually edit one.
Outbound message
A SOAP message from Salesforce to an external Web service. You can send
outbound messages from a workflow rule or Apex.
Package
See Force Platform AppExchange package on page 239
Page layout
The organization of fields, custom links, related lists, and other components on
a record detail or edit page. Use page layouts primarily for organizing pages for
your users, rather than for security.
Partner WSDL
A loosely-typed WSDL for customers, partners, and ISVs who want to build an
integration or a Force Platform AppExchange app that can work across multiple
Salesforce organizations. With this WSDL, the developer is responsible for
marshaling data in the correct object representation, which typically involves
editing the XML. However, you're also freed from being dependent on any
particular data model or Salesforce organization. See also Enterprise WSDL on
page 238.
Personal Edition
A free Salesforce edition designed for an individual sales representative or other
single user. Personal Edition provides access to key contact management features
such as accounts, contacts, and synchronization with Outlook. It also provides
sales representatives with critical sales tools such as opportunities.
Picklist
A selection list of options available for specific fields, for example, the Country
field for a Candidate object. Users can choose a single value from a list of options
rather than make an entry directly in the field.
Picklist values
The selections displayed in drop-down lists for particular fields. Some values come
predefined, and other values can be changed or defined by an administrator.
Platform Edition
A Salesforce edition based on either Enterprise Edition or Unlimited Edition that
does not include any of the standard Salesforce CRM apps, such as Sales or Service
& Support.
242
Glossary
Primary key
A relational database concept. Each table in a relational database has a field in
which the data value uniquely identifies the record. This field is called the primary
key. The relationship is made between two tables by matching the values of the
foreign key in one table with the values of the primary key in another. See also
Foreign key on page 239.
Production organization
A Salesforce organization that has live users accessing data.
Professional Edition
A Salesforce edition designed for businesses who need full-featured CRM
functionality. Professional Edition includes straightforward and easy-to-use
customization, integration, and administration tools to facilitate any small- to
mid-sized deployment.
Profile
A component of the platform that defines a user’s permission to perform different
functions. The platform includes a set of standard profiles with every organization,
and administrators can also define custom profiles to satisfy business needs.
Query locator
A parameter returned from the query() or queryMore() API call that
specifies the index of the last result record that was returned.
Query string parameter
A name-value pair that's included in a URL, typically after a '?' character. For
example:
http://na1.salesforce.com/001/e?name=value
Queue
A collection of records that don't have an owner. Users who have access to a queue
can examine every record that's in it and claim ownership of the records they want.
Quirks mode
A browser implementation that supports legacy Web pages that rely on Web
browsers' incomplete or incorrect implementations of HTML and CSS to display
properly. Browsers revert to quirks mode if you forget to set the DOCTYPE properly
at the top of a Web page, or if you don't use well-formed HTML. See also
Standards mode on page 245.
Record
A single instance of an object. For example, Software Engineer is a single Position
object record.
Record-level security
A method of controlling data in which we can allow particular users to view and
edit an object, but then restrict the individual object records that they're allowed
to see. See also Organization-wide defaults on page 242, Role hierarchy on page 244,
Sharing rules on page 245, and Manual sharing on page 241.
Related list
A section of a record or other detail page that lists items related to that record.
243
Glossary
Relationship
A connection between two objects in which matching values in a specified field
in both objects are used to link related data. For example, if one object stores data
about companies and another object stores data about people, a relationship allows
you to find out which people work at the company.
Role hierarchy
A record-level security setting that defines different levels of users such that users
at higher levels can view and edit information owned by or shared with users
beneath them in the role hierarchy, regardless of the organization-wide sharing
model settings. See also Record-level security on page 243.
Running user
The user whose security settings determine what data is displayed in a dashboard.
Because only one running user is specified per dashboard, everyone who can access
the dashboard sees the same data, regardless of their personal security settings.
S-Control
A component that allows you to embed custom HTML and JavaScript into
Salesforce detail pages, custom links, Web tabs, or custom buttons. For example,
you can define a custom s-control containing JavaScript and address merge fields
to display a map of a contact's address. See also HTML s-control on page 239, URL
s-control on page 246, and Snippet on page 245.
Salesforce.com Ideas
A forum where salesforce.com customers can suggest new product concepts,
promote favorite enhancements, interact with product managers and other
customers, and preview what salesforce.com is planning to deliver in future releases.
Visit Salesforce.com Ideas at ideas.salesforce.com.
Sandbox organization
A nearly identical copy of a Salesforce production organization. You can create
multiple sandboxes in separate environments for a variety of purposes, such as
testing and training, without compromising the data and applications in your
production environment.
Salesforce SOA (Service-Oriented Architecture)
A powerful capability of Apex that allows you to make calls to external Web
services from within Apex code.
Search layout
The organization of fields included in search results, lookup dialogs, and the recent
items lists on tab home pages.
Session ID
An authentication token that's returned when a user successfully logs in to
Salesforce. The Session ID prevents a user from having to log in again every time
he or she wants to perform another action in Salesforce.
Session timeout
The amount of time a single session ID remains valid before expiring. While a
session is always valid for a user while he or she is working in the Web interface,
sessions instantiated via the API expire after the duration of the session timeout,
regardless of how many transactions are still taking place.
244
Glossary
Sharing model
A security model that defines the default organization-wide access levels that users
have to each other’s information.
Sharing rules
Rules that allow an administrator to specify that all information created by users
within a given group or role is automatically shared to the members of another
group or role. Sharing rules also allow administrators to make automatic exceptions
to org-wide defaults for particular groups of users.
Snippet
A type of s-control that's designed to be included in other s-controls. Similar to
a helper method that is used by other methods in a piece of code, a snippet allows
you to maintain a single copy of HTML or JavaScript that you can reuse in multiple
s-controls. See also S-Control on page 244.
SOAP (Simple Object Access Protocol)
A protocol that defines a uniform way of passing XML-encoded data.
SOQL (Salesforce Object Query Language)
A query language that allows you to construct simple but powerful query strings
and to specify the criteria that should be used to select the data from the database.
SoqlXplorer
A lightweight, OS-X-based tool that lets you graphically browse the schema within
your organization, and build and test SOQL queries.
SOSL (Salesforce Object Search Language)
A query language that allows you to perform text-based searches using the API.
Standard object
A built-in object included with the Force Platform. You can also build custom
objects to store information that's unique to your app. See also Custom object on
page 237 and Object on page 241.
Standards mode
A browser implementation that respects all parts of the HTML and CSS language
specifications. To use standards mode, you must set the DOCTYPE properly at the
top of a Web page. See also Quirks mode on page 243.
Tab
An interface item that allows you to navigate around an app. A tab serves as the
starting point for viewing, editing, and entering information for a particular object.
When you click a tab at the top of the page, the corresponding tab home page for
that object appears.
Test method
An Apex class method that verifies whether a particular piece of code is working
properly. Test methods take no arguments, commit no data to the database, and
can be executed by the runTests() system method either via the command
line or in an Apex IDE, such as Eclipse with the Force Platform IDE.
Time-dependent workflow action
A workflow action that occurs before or after a certain amount of time has elapsed.
Time-dependent workflow actions can fire tasks, field updates, outbound messages,
and email alerts while the condition of a workflow rule remains true.
245
Glossary
Time trigger
A setting that defines when time-dependent workflow actions should fire.
Trigger
A piece of Apex that executes before or after records of a particular type are
inserted, updated, or deleted from the database. Every trigger runs with a set of
context variables that provide access to the records that caused the trigger to fire,
and all triggers run in bulk mode—that is, they process several records at once,
rather than just one record at a time.
Trigger context variables
Default variables that provide access to information about the trigger and the
records that caused it to fire.
Unit test
See Test method on page 245
Unlimited Edition
A Salesforce edition designed to extend customer success through the entire
enterprise. Unlimited Edition includes all Enterprise Edition functionality, plus
Apex, Force Platform Sandbox, Force Platform Mobile, premium support, and
additional storage.
Unmanaged package
A Force Platform AppExchange package that cannot be upgraded or controlled
by its developer. Unmanaged packages allow you to take any app components and
move them "as is" to AppExchange without going through a lengthy publishing
process.They're ideal for moving components between organizations for a one-time
transfer.
URL (Uniform Resource Locator)
The global address of a website, document, or other resource on the Internet. For
example, http://www.salesforce.com.
URL s-control
An S-Control that contains an external URL that hosts the HTML that should
be rendered on a page. When saved this way, the HTML is hosted and run by an
external website. URL s-controls are also called Web controls. See also S-Control
on page 244.
Validation rule
A rule that prevents a record from being saved if it does not meet the standards
that are specified.
Visualforce
A simple, tag-based markup language that allows developers to easily define custom
pages and components for apps built on the platform. Each tag corresponds to a
coarse or fine-grained component, such as a section of a page, a related list, or a
field. The components can either be controlled by the same logic that's used in
standard Salesforce pages, or developers can associate their own logic with a
controller written in Apex.
Web control
See URL s-control on page 246.
246
Glossary
Web service
A mechanism by which two applications can easily exchange data over the Internet,
even if they run on different platforms, are written in different languages, or are
geographically remote from each other.
WebService method
An Apex class method or variable that can be used by external systems, such as
an s-control or mash-up with a third-party application. Web service methods must
be defined in a global class.
Web tab
A custom tab that allows your users to use external websites from within the
application.
Wizard
Any tool with a user interface that leads a user through a complex task in multiple
steps.
Workflow action
An email alert, field update, outbound message, or task that fires when the
conditions of a workflow rule are met.
Workflow email alert
A workflow action that sends an email when a workflow rule is triggered. Unlike
workflow tasks, which can only be assigned to application users, workflow alerts
can be sent to any user or contact, as long as they have a valid email address.
Workflow field update
A workflow action that changes the value of a particular field on a record when a
workflow rule is triggered.
Workflow outbound message
A workflow action that sends data to an external Web service, such as another
cloud computing application. Outbound messages are used primarily with
composite apps.
Workflow queue
A list of workflow actions that are scheduled to fire based on workflow rules that
have one or more time-dependent workflow actions.
Workflow rule
A "container" for a set of workflow instructions that includes the criteria for when
the workflow should be activated, as well as the particular tasks, alerts, and field
updates that should take place when the criteria for that rule are met.
Workflow task
A workflow action that assigns a task to an application user when a workflow rule
is triggered.
Wrapper class
A class that abstracts common API functions such as logging in, managing sessions,
and querying and batching records. A wrapper class makes your integration more
straightforward to develop and maintain, keeps the logic necessary to make API
calls in one place, and affords easy reuse across all components that require API
access.
247
Glossary
248
About the Authors
Mysti Berry is a Lead Technical Writer at salesforce.com, focused on the Force Platform API
and the Force Platform AJAX Toolkit. Mysti has 18 years experience in technical writing, the
last three spent on the Force Platform. She earned a B.A. in linguistics from University of
California Santa Cruz and an M.F.A. from University of San Francisco. She teaches technical
writing courses at University of California Berkeley Extension.
Phil Choi is a Staff Technical Writer at salesforce.com, focusing on platform features including
workflow and approvals, as well as Force Platform Sites. Phil earned a B.S. in Mechanical
Engineering from The Pennsylvania State University and an M.F.A. in creative writing from
Emerson College.
Leah Cutter is a Staff Technical Writer at salesforce.com, focused on Apex. Leah has a degree
in Computer Science and another in English Literature from the University of Minnesota.
Mark Leonard is a Senior Technical Writer at salesforce.com, focused on the Force Platform
Metadata API. Mark earned a B.E. in Electronic Engineering from University College Dublin
and a M. Sc. by Research in Electronic Engineering from University of Dublin, Trinity College.
Chris McGuire is a Staff Technical Writer at salesforce.com, focused on the Force Platform.
He is also a coauthor of Force Platform Fundamentals: An Introduction to Custom Application
Development in the Cloud.
249
About the Authors
250
Index
Index
$ObjectType merge variable 17, 20 Approval processes 11, 87
else option 83
parallel approvers 83
A Architecture, client application 225
About this book 1 Asynchronous outbound messages 89
Accounts, mass updating contacts 147 tracking 92
Adobe Flex 196 Attributes, SObject 96, 99
AJAX 196 Authenticating calls to the API 201
in Visualforce pages 141 Averages, roll-up summary fields 128
updating a page 48
AJAX Toolkit 13, 17, 20 B
AJAX Tools 6
Alerts, workflow 10 Batching records for API calls 207
Anonymous execution, Apex 12 Bulk processing, trigger 149, 154
anti-join 116 Buttons
Any array, Partner WSDL 199 creating detail page 23
Apex 87 creating mass delete 17
about 12 creating mass update 20
creating a button 25 creating with Apex 25
creating a trigger for the mobile application overriding with Visualforce 27
177 window open properties 24
documentation 5
dynamic 73
integrating applications 195
C
preventing duplicate records 154 C#.NET 196
properties 143 using the Partner WSDL 199
triggers 149, 150, 153, 154, 160 Certificates, client 198
Apex WSDL 197 Child records
API creation from parent 160
batching records 207 mass updating 147
client applications 223 Classes, Apex 12
documentation 5 Client applications 223
integrating applications 195 configuration files 228
introduction 13 SOAP message compression 228
login() call 201 Client certificates 198
metadata introduction 14 Client classes, API 210, 226
query() 206 Code samples, book 4
queryMore() 206 commandAction tag, Visualforce 33
session ID 201 commandButton tag, Visualforce 41
setting the session timeout value 205 commandLink tag, Visualforce 141
setting up 196 Compression, SOAP message 228
wrapper classes 210, 226 Concatenate 130
API Only permission 196 conditional overrides 53
API queries and searches 95 Configuration files 228
251
Index
252
Index
J N
Java 196 Native functionality 9
batching records 207 Navigation in Visualforce pages 35
query/queryMore pattern implementation 206
253
Index
O R
Objects Records
about 9 bulk processing in a trigger 149
attributes 96, 99 ID prefixes 96
frontdoor URLs 96 locking 133
ID prefixes 96 preventing duplicates with Apex 154
Operators, concatenate 130 Recruiting app, sample 3
Organization-wide defaults 10 Recursive triggers, controlling 150
Outbound messages, asynchronous 89 REGEX() function 125
tracking 92 Related records, fields 130
Outer joins in SOQL 116 relatedList tag, Visualforce 139, 141
outputLabel tag, Visualforce 41 Relationships
outputLink tag, Visualforce 139 about 10
outputPanel tag, Visualforce 42 many-to-many 121
traversing in SOQL 105
viewing SObject 96, 99
P Relative date literals 108
Page layouts 11 Reports 11
pageReference class, Visualforce 41 reRender attribute, Visualforce 141
Pages, overriding with Visualforce 46 Role hierarchy 10
panelGrid tag, Visualforce 41, 42 Roll-up summary fields 128
panelGroup tag, Visualforce 42 in cross-object formulas 133
param tag, Visualforce 139 Ruby on Rails 196
Partner WSDL 197 Rules
using 199 sharing 10
Password Never Expires permission 196 validation 10
Perl 196 workflow 10
Permissions runAs method 161
about 10
API Only 196 S
Modify All Data 196
Password Never Expires 196 Salesforce instance 201
Person accounts, finding records 106 Salesforce Mobil 13
PHP 196 SAML 189
batching records 207 Samples, book code 4
Point-and-click setup tools 9 search() 101
Prefixes, record ID 96 Searching and querying data 95
Previewing query results 110 Security settings 10
Processes, approval 11 semi-join 116
Profiles, user 10 Session ID, API 201
Python 196 Sessions
managing 204
setting the timeout value 205
Q Sharing rules 10
Queries, previewing results 110 Single sign on 165
Query string parameters, Visualforce 139 Single sign-on 189
query() 101 Sites
query/queryMore pattern 206 branding 68
CNAME 64
254
Index
255
Index
256