Obama '08

               
   

Go Back   Mike Simonds > Salesforce > Salesforce PHP Tutorials

This is a discussion on Using Salesforce Outbound SOAP Messages with PHP within the Salesforce PHP Tutorials forums, part of the Salesforce category; Recently I have been using the Salesforce outbound SOAP messages while I

Reply
 
LinkBack (1) Thread Tools Rate Thread
  #1  
Old 05-13-2008, 09:19 AM
Administrator
 
Join Date: May 2007
Posts: 248
Send a message via AIM to mike Send a message via MSN to mike Send a message via Yahoo to mike Send a message via Skype™ to mike
Using Salesforce Outbound SOAP Messages with PHP

Recently I have been using the Salesforce outbound SOAP messages while I was working on some workflow's. Honestly I had no idea that this could be implemented and I am in awe right now.

My organization needed to find a way to change the Owner Id on a custom object when a certain field changed. We implemented a workflow, which in turn would thin trigger an outbound message from Salesforce via the API. An outbound message looks like and is formatted in XML. Here is an example:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <notifications xmlns="http://soap.sforce.com/2005/09/outbound">
   <OrganizationId>00DR......</OrganizationId>
   <ActionId>04kR00000004CCXIA2</ActionId>
   <SessionId xsi:nil="true"/>
   <EnterpriseUrl>https://cs2-api.salesforce.com/services/Soap/c/8.0/4e1300DR00000000XcD</EnterpriseUrl>
   <PartnerUrl>https://cs2-api.salesforce.com/services/Soap/u/8.0/4e1300DR00000000XcD</PartnerUrl>
   <Notification>
    <Id>04lR0000000CcIFIA0</Id>
    <sObject xsi:type="sf:Design_Registration__c" xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
     <sf:Id>a06R00000009QZaIAM</sf:Id>
     <sf:BU_Reviewer_Lookup__c>00540000000lnc2AAA</sf:BU_Reviewer_Lookup__c>
     <sf:DP_cust_eng_email__c>me@email.com</sf:DP_cust_eng_email__c>
     <sf:DP_reg_id__c>JXD08-7CLLB7</sf:DP_reg_id__c>
     <sf:DR_Number__c>R080500453</sf:DR_Number__c>
     <sf:Field_reviewer_lookup__c>00540000000yHbGAAU</sf:Field_reviewer_lookup__c>
     <sf:Name>URT</sf:Name>
     <sf:OwnerId>00540000000mBqsAAE</sf:OwnerId>
    </sObject>
   </Notification>
  </notifications>
 </soapenv:Body>
</soapenv:Envelope>
The key to this is that you are allowed to include almost any field in the outbound message. You can set these values when you are creating the trigger in Salesforce.

Once you set the fields, they are sent in the sObject portion of the SOAP message:

Code:
<sObject xsi:type="sf:Design_Registration__c" xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
     <sf:Id>a06R00000009QZaIAM</sf:Id>
     <sf:BU_Reviewer_Lookup__c>00540000000lnc2AAA</sf:BU_Reviewer_Lookup__c>
     <sf:DP_cust_eng_email__c>me@email.com</sf:DP_cust_eng_email__c>
     <sf:DP_reg_id__c>JXD08-7CLLB7</sf:DP_reg_id__c>
     <sf:DR_Number__c>R080500453</sf:DR_Number__c>
     <sf:Field_reviewer_lookup__c>00540000000yHbGAAU</sf:Field_reviewer_lookup__c>
     <sf:Name>URT</sf:Name>
     <sf:OwnerId>00540000000mBqsAAE</sf:OwnerId>
    </sObject>
The great thing is that you can then kick off almost any application with this with a SOAP Server that is setup locally (we have one running on our server).

The key is that you have to send a response back to your instance of Salesforce.

So once the SOAP Server is setup on your server, you can respond to an incoming message like this:

PHP Code:
//Reads SOAP incoming message from Salesforce/MAPS
$data fopen('php://input','rb');
$content fread($data,5000); 
This code reads the raw data coming in from Salesforce and then sticks it in a variable called $content.

You can then respond to the message like this:

PHP Code:
if ($content)
{
    respond('true');
}
else
{
    respond('false');
}

function respond($tf)
{

    print '<?xml version "1.0" encoding "utf-8"?>
   <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
       <soapenv:Body>
           <notifications xmlns="http://soap.sforce.com/2005/09/outbound">
               <Ack>' . $tf . '</Ack>
              </notifications>
          </soapenv:Body>
      </soapenv:Envelope>';
}
So $tf is set to true and responds to the outbound message and Salesforce knows that the message has been accepted and is removed from the queue.


So what can you really do with this? We are using this workflow to change the OwnerId on a custom object when a certain field is changed

I will continue to update this thread with different topics and ideas on what I have been able to accomplish with this on demand feature

~Mike
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote

  #2  
Old 05-13-2008, 11:50 AM
Junior Member
 
Join Date: May 2008
Posts: 9

What does it take to get a SOAP server setup? What's needed architecturally to configure the end point? Just any PHP server that is ready and able to connect to Salesforce using the PHP toolkit?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #3  
Old 05-13-2008, 02:12 PM
Administrator
 
Join Date: May 2007
Posts: 248
Send a message via AIM to mike Send a message via MSN to mike Send a message via Yahoo to mike Send a message via Skype™ to mike

Hey Scott !!

listen the setup (still totally new at this) was rather quite easy

First off, do you know how to setup the outbound workflow in Salesforce?

I am sure you do, you are a lot more knowledgeable than I am, LOL!

Listen there is no special setup for the SOAP server setup.

I just have that code that I posted in the first post of this thread and a parser to read XML (the incoming SOAP message)

for testing purposes, I wrote it out to a file and then used that to parse the XML until I felt comfortable with the data I was seeing using print_r.

You can use PHP's built in XML DOM. I found this example at the salesforce forums:

PHP Code:
<?php
/* Handles SFDC Outbound Message notification.*/
require_once ('../includes/salesforce_login.php');


// Get raw post data
$data fopen('php://input','rb');
$content fread($data,5000);

// Parse values from soap string
$dom = new DOMDocument();
$dom->loadXML($content);
$resultArray parseNotification($dom);
$sObject $resultArray["sObject"];

// Output field names and values to file
$fields_string "";

foreach (
$sObject->fieldnames as $field)
{
    
$fields_string .= $field " => " $sObject->fields->$field "\n";
}


// Write message and values to a file
$fh fopen('soap.xml','a');
fwrite($fh,$content);
$ret fclose($fh);


// Sends SOAP response to SFDC
if ($ret)
{
    
respond('true');
}
else
{
    
respond('false');
}
//functions

/* Parse a Salesforce.com Outbound Message notification SOAP packet
* into an array of notification parms and an sObject.   */
function parseNotification($domDoc)
{
    
// Parse Notification parameters into result array
    
$result = array("OrganizationId" => "","ActionId" => "","SessionId" => "","EnterpriseUrl" => "","PartnerUrl" => "","sObject" => null);

    
$result["OrganizationId"] = $domDoc->getElementsByTagName("OrganizationId")->item(0)->textContent;
    
$result["ActionId"] = $domDoc->getElementsByTagName("ActionId")->item(0)->textContent;
    
$result["SessionId"] = $domDoc->getElementsByTagName("SessionId")->item(0)->textContent;
    
$result["EnterpriseUrl"] = $domDoc->getElementsByTagName("EnterpriseUrl")->item(0)->textContent;
    
$result["PartnerUrl"] = $domDoc->getElementsByTagName("PartnerUrl")->item(0)->textContent;

    
// Create sObject and fill fields provided in notification
    
$sObjectNode $domDoc->getElementsByTagName("sObject")->item(0);
    
$sObjType $sObjectNode->getAttribute("type");
    if (
substr_count($sObjType,"sf:"))
        
$sObjType substr($sObjType,3);
    
$result["sObject"] = new SObject($sObjType);
    
$result["sObject"]->type $sObjType;

    
$sObjectNodes $domDoc->getElementsByTagNameNS('urn:sobject.enterprise.soap.sforce.com','*');
    
$result["sObject"]->fieldnames = array();
    foreach (
$sObjectNodes as $node)
    {
        if (
$node->localName == "Id")
        { 
// Id goes under sObject->Id
            
$result["sObject"]->Id $node->textContent;
        }
        else
        { 
// ... the rest go under sObject->fields
            
$fieldname $node->localName;
            
$result["sObject"]->fields->$fieldname $node->nodeValue;
            
array_push($result["sObject"]->fieldnames,$fieldname);
        }
    }

    return 
$result;
// end parseNotification


function respond($tf)
{

    print 
'<?xml version = "1.0" encoding = "utf-8"?>
   <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
       <soapenv:Body>
           <notifications xmlns="http://soap.sforce.com/2005/09/outbound">
               <Ack>' 
$tf '</Ack>
              </notifications>
          </soapenv:Body>
      </soapenv:Envelope>'
;
}
?>
to get me started. I had some small troubles and also purchased a off the shelf XML parser that reads the SOAP message better than the DOM XML built in class.

So basically it is easy to setup and get working, I can take this offline sometime if you want

~Mike

PS: good to see you here, I need to add a link to your site on my main page, I forgot to do that
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #4  
Old 05-13-2008, 04:46 PM
Junior Member
 
Join Date: May 2008
Posts: 9

Awesome. Got it working! Now I need to figure out what to implement, but this is a really nice option to have.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #5  
Old 05-13-2008, 05:03 PM
Administrator
 
Join Date: May 2007
Posts: 248
Send a message via AIM to mike Send a message via MSN to mike Send a message via Yahoo to mike Send a message via Skype™ to mike

Outstanding man!! Glad that helped.

Listen if you come up with Ideas, fixes or things that work and you post them on your site, would you be willing to post a link here or the code and let me know what you did or found?

FYI > I added a link from my main menu to your site


~Mike
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #6  
Old 06-26-2008, 01:26 PM
Administrator
 
Join Date: May 2007
Posts: 248
Send a message via AIM to mike Send a message via MSN to mike Send a message via Yahoo to mike Send a message via Skype™ to mike

Scott we have taken this service and added a whole new object via the outbound messaging. It is really like combining a whole bunch of queries using the data coming in from the salesforce outbound messaging and querying multiple tables

Then we take that data and create a whole new data flow for a new Object in Salesforce. It works like a charm

So if they change a status on the custom object, it kicks off a SOAP outbound message that you could really do anything with!!

Stick it into a custom reporting application, A database, or back into Salesforce

I am thinking this is like the new trigger function in APEX, but keeping your process outside of Salesforce and not having to learn APEX coding (even though I need too)

Have you had a chance to mess around with this at all

~Mike
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #7  
Old 07-09-2008, 09:42 AM
Administrator
 
Join Date: May 2007
Posts: 248
Send a message via AIM to mike Send a message via MSN to mike Send a message via Yahoo to mike Send a message via Skype™ to mike

One item that I did not take into consideration was error reporting and what it can cause in your responses to salesforce's outbound messaging queue

Let me explain

Last week I was running into errors when sending 10 fields in an outbound message and forgot to account for empty fields in the data elements.

So let's say you send the following from the Account Object:

* FirstName
* LastName
* Name
* Email
* UserName
* Phone
* Mobile


And in some cases not all the data is populated, well if your error_reporting is turned on and you do not set it correctly to ignore notice's, you can run into some serious problems trying to get the outbound message queue from clearing out.

I was sending notices back to Salesforce with the True response and noticing that the message queue was filled up with many requests.

A fellow developer at work told me to check what was in the output buffer, basically what I was sending back to salesforce

I had no idea that the notices were being sent back, but once I added the mail() function to email myself the ob_get_contents(), I saw the other data that I was returning to Salesforce, what a mess that was!

a simple line at the top of the script to turn off notice reporting was all that I needed

PHP Code:
error_reporting(E_ALL E_NOTICE); 
Stupid mistake, but I thought that I would share it with the community because you could run into the same problems

Anyway just a little snippet to take care of clearing out the buffer before sending your response to Salesforce
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #8  
Old 08-05-2008, 08:20 AM
Junior Member
 
Join Date: Aug 2008
Posts: 1
Thanks for the great advice - now a followup question

This thread has been my primary resource for outbound messaging via SalesForce. Thanks for all the great input.

My client has 2 primary means of accessing their SalesForce data:
1. Through the web at login.salesforce.com, na2.salesforce.com, etc. using SF's snazzy Ajax interface.
2. Through a custom CMS web app designed to talk to salesforce through the web service API.

My question is: apart from having 2 different logins, how do I tell the 2 kinds of requests apart?

Let's take this scenario: I modify the Contact object through the CMS (case 2 above). This forces the CMS to push the changes to the salesforce database. I have an outbound message being triggered for all changes to a Contact object. The outbound message gets triggered and notifies the CMS that the Contact object has changed, even though the CMS initiated the change in the first place.

How do I keep salesforce from generating the outbound message when it was triggered by an event via a webservice API call?

Thanks in advance,
/a
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #9  
Old 08-05-2008, 02:09 PM
Administrator
 
Join Date: May 2007
Posts: 248
Send a message via AIM to mike Send a message via MSN to mike Send a message via Yahoo to mike Send a message via Skype™ to mike

Quote:
Originally Posted by ambiguator View Post
This thread has been my primary resource for outbound messaging via SalesForce. Thanks for all the great input.

My client has 2 primary means of accessing their SalesForce data:
1. Through the web at login.salesforce.com, na2.salesforce.com, etc. using SF's snazzy Ajax interface.
2. Through a custom CMS web app designed to talk to salesforce through the web service API.

My question is: apart from having 2 different logins, how do I tell the 2 kinds of requests apart?

Let's take this scenario: I modify the Contact object through the CMS (case 2 above). This forces the CMS to push the changes to the salesforce database. I have an outbound message being triggered for all changes to a Contact object. The outbound message gets triggered and notifies the CMS that the Contact object has changed, even though the CMS initiated the change in the first place.

How do I keep salesforce from generating the outbound message when it was triggered by an event via a webservice API call?

Thanks in advance,
/a

When you create an outbound message, you can set who you want to send the outbound message as, a user id, like me (see the attached picture)

Maybe you could use 2 different users to send as, thus two different identifications that you can use to differentiate the two outbound messages.

I did not know that you could kick off a outbound message via an API call, but you can limit it to only being called once!

when you set the Work Flow rule, there is a section:

Evaluate rule How do I choose?
  1. When a record is created, or when a record is edited and did not previously meet the rule criteria (choose this one)
  2. Only when a record is created
  3. Every time a record is created or edited
Hope that helps sir and I hope that I understood your question(s)

If Not then do let me know
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #10  
Old 08-09-2008, 09:05 AM
Administrator
 
Join Date: May 2007
Posts: 248
Send a message via AIM to mike Send a message via MSN to mike Send a message via Yahoo to mike Send a message via Skype™ to mike

Yesterday I came across a major problem with one of our outbound soap processes that I would like to bring up.

I knew that Salesforce assigned a processing Id with their outbound message, which makes since. I always thought that this was a 1 for 1 relationship, but I am totally mistaken.

We had a discrepancy in some of our counts in two different objects and could not figure it out. Further testing revealed that Salesforce can send multiple records with one processing Id. Look at the XML code below from one processing Id:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soapenv:Body>
  <notifications xmlns="http://soap.sforce.com/2005/09/outbound">
   <OrganizationId>*****************</OrganizationId>
   <ActionId>04k400000004CYMAA2</ActionId>
   <SessionId xsi:nil="true"/>
   <EnterpriseUrl>https://cs2-api.salesforce.com/services/Soap/c/8.0/</EnterpriseUrl>
   <PartnerUrl>https://cs2-api.salesforce.com/services/Soap/u/8.0/</PartnerUrl>
   <Notification>
    <Id>04lR00000004z4uIAA</Id>
    <sObject xsi:type="sf:OpportunityLineItem" xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
     <sf:Id>00k40000004PHXtAAO</sf:Id>
    </sObject>
   </Notification>
   <Notification>
    <Id>04lR00000004z4qIAA</Id>
    <sObject xsi:type="sf:OpportunityLineItem" xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
     <sf:Id>00k40000004P5IhAAK</sf:Id>
     </sObject>
   </Notification>
   <Notification>
    <Id>04lR00000004z4vIAA</Id>
    <sObject xsi:type="sf:OpportunityLineItem" xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
     <sf:Id>00k40000004PK51AAG</sf:Id>
    </sObject>
   </Notification>
 </soapenv:Body>
</soapenv:Envelope>
I wrote the script on the basis of the 1 to 1 relationship and hence, it could not. I will rewrite it on Monday morning so it can iterate through multiple line items and process all the SOAP inbound messages. This will allow for mutliple records to process

Just be aware that there is a 1 to many relationship when it comes to SOAP messages from Salesforce and adjust your processes accordingly.


I will keep this thread updated with the changes and let you know how it goes

~Mike
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump

LinkBacks (?)
LinkBack to this Thread: http://www.mikesimonds.com/using-salesforce-outbound-soap-messages-php-t95.html
Posted By For Type Date
Community - Outbound Messaging SOAPServer in PHP - Perl, PHP, Python & Ruby Development - Salesforce.com Community This thread Refback 08-25-2008 10:40 AM



Powered by vBulletin


SEO by vBSEO 3.2.0 RC8 ©2008, Crawlability, Inc.

1 2 3 4 5