2. Safe Harbor
Safe harbor statement under the Private Securities Litigation Reform Act of 1995: This presentation may contain forward-looking
statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of the assumptions proves
incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking
statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections
of subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for
future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and
customer contracts or use of our services.
The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new
functionality for our service, our new business model, our past operating losses, possible fluctuations in our operating results and rate of
growth, interruptions or delays in our Web hosting, breach of our security measures, risks associated with possible mergers and
acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate
our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling
non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could
affect the financial results of salesforce.com, inc. is included in our annual report on Form 10-K for the most recent fiscal quarter ended
July 31, 2011. This document and others are available on the SEC Filings section of the Investor Information section of our Web site.
Any unreleased services or features referenced in this or other press releases or public statements are not currently available and may
not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that
are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
5. Salesforce1 Platform
6B
Lines of Apex
500M
API Calls
Per Day
4M+
Apps Built on
the Platform
72B
Records
Stored
Salesforce is a Platform Company. Period.
-Alex Williams, TechCrunch
6. Salesforce1 Platform
APIs
REST APIs
Bulk
APIs
Tooling
APIs
Metadata
APIs
Analytics
APIs
Social
APIs
ET API
Streaming
APIs
Mobile
SDK
Mobile
Packs
Offline
Support
Geolocation
Custom
Actions
Identity
Private App
Exchange
Mobile
Notifications
Visualforce
1
Chatter
Mobile
Services
SOAP
APIs
Workflows
Analytics
Apex
Multilanguage
Heroku
Add-Ons
Email
Service
s
ET 1:1
ET Fuel
Multi-tenant
Cloud
Database
Data-level
Security
Schema
Builder
Sharing
Model
Translation
Workbench
Search
Heroku1
Monitoring
Core Services
23. Reducing Viewstate
//Transient data that does not get sent back,
//reduces viewstate
transient String userName {get; set;}
//Static and/or private vars
//also do not become part of the viewstate
static private integer VERSION_NUMBER = 1;
24. Reducing Viewstate
//Asynchronous JavaScript callback. No viewstate.
//RemoteAction is static, so has no access to Controller context
@RemoteAction
public static Account retrieveAccount(ID accountId) {
try {
Account a = [SELECT ID, Name from ACCOUNT
WHERE Id =:accountID LIMIT 1];
return a;
} catch (DMLException e) {
return null;
}
}
25. Handling Parameters
//check the existence of the query parameter
if(ApexPages.currentPage().getParameters().containsKey(„id‟)) {
try {
Id aid = ApexPages.currentPage().getParameters().get(„id‟);
Account a =
[SELECT Id, Name, BillingStreet FROM Account
WHERE ID =: aid];
} catch(QueryException ex) {
ApexPages.addMessage(new ApexPages.Message(
ApexPages.Severity.FATAL, ex.getMessage()));
return;
}
}
26. SOQL Injection
String account_name = ApexPages.currentPage().getParameters().get('name');
account_name = String.escapeSingleQuotes(account_name);
List<Account> accounts = Database.query('SELECT ID FROM
Account WHERE Name = '+account_name);
27. Cookies
//Cookie =
//new Cookie(String name, String value, String path,
//
Integer milliseconds, Boolean isHTTPSOnly)
public PageReference setCookies() {
Cookie companyName =
new Cookie('accountName','TestCo',null,315569260,false);
ApexPages.currentPage().setCookies(new Cookie[]{companyName});
return null;
}
public String getCookieValue() {
return ApexPages.currentPage().
getCookies().get('accountName').getValue();
}
28. Inheritance and Construction
public with sharing class PageController
implements SiteController {
public PageController() {
}
public PageController(ApexPages.StandardController stc) {
}
29. Controlling Redirect
//Stay on same page
return null;
//New page, no Viewstate
PageReference newPage = new Page.NewPage();
newPage.setRedirect(true);
return newPage;
//New page, retain Viewstate
PageReference newPage = new Page.NewPage();
newPage.setRedirect(false);
return newPage;
30. Unit Testing Pages
//Set test page
Test.setCurrentPage(Page.VisualforcePage);
//Set test data
Account a = new Account(Name='TestCo');
insert a;
//Set test params
ApexPages.currentPage().getParameters().put('id',a.Id);
//Instatiate Controller
SomeController controller = new SomeController();
//Make assertion
System.assertEquals(controller.AccountId,a.Id)
41. Canvas Anatomy
Any Language, Any Platform
•
•
•
•
•
Only has to be accessible from the user’s browser
Authentication via OAuth or Signed Response
JavaScript based SDK can be associated with any language
Within Canvas, the App can make API calls as the current user
apex:CanvasApp allows embedding via Visualforce
42. Integrating Your Web Applications in Salesforce1 with
Force.com Canvas
http://bit.ly/1n8C4WK
Time: 45 Minutes
46. Controlling Flow
trigger LineItemTrigger on Line_Item__c (before insert,
before update) {
//separate before and after
if(Trigger.isBefore) {
//separate events
if(Trigger.isInsert) {
System.debug(„BEFORE INSERT‟);
DelegateClass.performLogic(Trigger.new);
//
47. Delegates
public class BlacklistFilterDelegate
{
public static Integer FEED_POST = 1;
public static Integer FEED_COMMENT = 2;
public static Integer USER_STATUS = 3;
List<PatternHelper> patterns {set; get;}
Map<Id, PatternHelper> matchedPosts {set; get;}
public BlacklistFilterDelegate()
{
patterns = new List<PatternHelper>();
matchedPosts = new Map<Id, PatternHelper>();
preparePatterns();
}
48. Static Flags
public with sharing class AccUpdatesControl {
// This class is used to set flag to prevent multiple calls
public static boolean calledOnce = false;
public static boolean ProdUpdateTrigger = false;
}
49. Chatter Triggers
trigger AddRegexTrigger on Blacklisted_Word__c (before insert, before update) {
for (Blacklisted_Word__c f : trigger.new)
{
if(f.Custom_Expression__c != NULL)
{
f.Word__c = '';
f.Match_Whole_Words_Only__c = false;
f.RegexValue__c = f.Custom_Expression__c;
}
else
f.RegexValue__c = RegexHelper.toRegex(f.Word__c,
f.Match_Whole_Words_Only__c);
}
}
54. Batchable Interface
global with sharing class WarehouseUtil
implements Database.Batchable<sObject> {
//Batch execute interface
global Database.QueryLocator start(Database.BatchableContext BC){
//Start on next context
}
global void execute(Database.BatchableContext BC,
List<sObject> scope) {
//Execute on current scope
}
global void finish(Database.BatchableContext BC) {
//Finish and clean up context
}
59. Apex SOAP
global class MyWebService {
webService static Id makeContact(String lastName, Account a) {
Contact c = new Contact(lastName = 'Weissman',
AccountId = a.Id);
insert c;
return c.id;
}
}
60. Apex REST
@RestResource(urlMapping='/CaseManagement/v1/*')
global with sharing class CaseMgmtService
{
@HttpPost
global static String attachPic(){
RestRequest req = RestContext.request;
RestResponse res = Restcontext.response;
Id caseId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
Blob picture = req.requestBody;
Attachment a = new Attachment (ParentId = caseId,
Body = picture,
ContentType = 'image/
62. Outgoing Email
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String body = count+' closed records older than 90 days have been deleted';
//Set addresses based on label
mail.setToAddresses(Label.emaillist.split(','));
mail.setSubject ('[Warehouse] Dated Invoices');
mail.setPlainTextBody(body);
//Send the email
Messaging.SendEmailResult [] r =
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
63. Incoming Email
global class PageHitsController implements Messaging.InboundEmailHandler {
global Messaging.InboundEmailResult handleInboundEmail(
Messaging.inboundEmail email,
Messaging.InboundEnvelope env)
{
if(email.textAttachments.size() > 0) {
Messaging.InboundEmail.TextAttachment csvDoc =
email.textAttachments[0];
PageHitsController.uploadCSVData(csvDoc.body);
}
Messaging.InboundEmailResult result = new
Messaging.InboundEmailResult();
result.success = true;
return result;
}
Change this slide to match the local internet requirements.The bit.ly link points to the latest HTML draft of the new workbook. This is different than the official workbook on developer.force.com and there are schema differences, so attendees cannot mix and match.
Here is an overview of what our data model will look like.
For when declarative logic is not enough, we provide Apex. Apex is a cloud-based programming language, very similar to Java – except that you can code, compile and deploy all right from your Salesforce instance. You’ll see how we can create robust programmatic functions right from your browser.
For those unfamiliar with OO, here’s what a simple class structure looks like. NOTE: If you’re using this slide deck for a very technical audience, breeze through this section and get to meatier features of Apex, otherwise go into a basic discussion about how Apex is divided into classes, refers to information with variables, etc.Now note however, the big difference – we can access and manipulate data with just a few lines of code, no additional configuration required. Apex will automatically know everything you’ve done declaratively for your application.
What do we mean by components? Well you’d start with a page component, and that will define how the whole page is going to be rendered. And then you can add things like a form and fields for the form. Now everything you see here will be HTML when it gets outputted. So you’d have and HTML form, HTML input tages, etc. To the browser, it is just standard HTML.But how are we binding data here? We define a controller, which gets access to server-side logic. Whenever you see these brackets and that exclamation point, you’re looking at dynamically bound data which will effect how the component is rendered.However, the server-side logic here is a little interesting. Do Standard Controller demo, then go back to describe custom controllers and extensions.
Now that you’ve seen how controllers normally look, let’s look at a different trick Visualforce has. You can also access server-side code directly via JavaScript. The Apex code is specified with the @RemoteAction annotation, and then we can call it from JavaScript easily. This is a very lightweight approach to communicating with data. You’ll see an example of this as part of the tutorial.
You can also create completely custom components with your own logic that utilize attributes you define. This makes your Visualforce portable and easy to maintain.
On the flip side, Visualforce also has template support, you can define a page and which sections can be utilized, and then another page can define those sections for the template.
Visualforce also has components specifically for duplicating the Chatter interface, if you want to use that with your pages.
Other uses for Visualforce include creating custom email templates, embedding Visualforce into existing layouts, rendering PDF instead of HTML, creating custom Mobile interfaces and also completely overriding a page.
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
Explain the ID trick, - for SOQL injection protection
Explain the ID trick, - for SOQL injection protection
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
We’re used to thinking about Visualforce as a component based library, and that let’s us create HTML based interfaces very quickly and easily by binding those components to data. But what about using those components to mix and match Visualforce across your instance?
For instance, you can use Visualforce to create very custom dashboards, and then put those on your homepage. Here’s an example I’ve got with the Warehouse app, which is showing recently created Invoices:( /home/home.jsp )Now if I click into one of those Invoices, we’re also seeing visualforce.
Because, and this is probably one of the more common use cases for Visualforce, anything with a Standard Controller can be used in place of the standard list, view, edit style pages. On this page, I’m still displaying the page layout via the detail component, but we wanted to be able to leverage a new footer across different detail pages(show WarehouseDetail
And we’re keeping that new detail consistent by using a template. We can define our inserts, and then define our content. This allows us to maintain a lot of different look and feels across different object types, but controlling the parts that will the same in one place.
And of course, as we customize that layout, we can create custom components which can take incoming attributes and then render what we need. For instance, in my footer I am using a visualization jQuery plugin called isotope, which allows us to view the line items in a very different way than the related list. You’ll see more about jQuery later.
And of course, if I want that Visualforce in the middle of my layout, I can use a StandardController to embed that right into it. In fact, in this layout – this section is not being generated here on Salesforce.
It’s actually using Canvas, which allows me to easily put third part applications into Salesforce in a secure manner.
For instance, maybe I have a large internal intranet applications. I don’t want to port all that functionality into Salesforce, but I do want to be able to integrate this one interface.
Apex controllers are probably the most common use case for the language, but triggers merit a second place.
And with all of those potentials triggers in your system, they can easily get out of hand. There are a few best practices people have found to make them more maintainable.First, consider having only one trigger per object. Within the trigger class itself, break out every possible event, before and after, and start putting system.debugs around them. At the very least, this will make it very easy to track down in debug logs where the logic is getting fired.Second, consider handing off the actual logic to delegate classes. Send them the current scope of the trigger and let them sort it out. This will neatly divide the functionality that your trigger is trying to accomplish.
A delegate also gives you more breathing room. Look at all the variables we are using to properly track what this delegate wants to do – if you started stacking all the logic into the trigger itself, this will start to get unruly really fast. Don’t let your triggers become a battleground, they should be more like highways.
Another trick is using static variables in another class to track progress in your trigger. Changes to these flags will be visible for the span of the trigger context. So if, for instance, another process kicks off your trigger logic a second time, and you don’t want it to – you could swap the first flag here to true, and then not execute any logic if that flag is true.
And remember one of the more powerful uses of triggers is in association with Chatter. Let’s take a look at a Force.com labs app, Chatter Blacklist, which illustrates this very well.
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?Self Service by Email
Update this subtitle
How does privacy work with Chatter? Can you accidentally share a record I’m not supposed to see?