+ Reply to Thread
Page 2 of 7 FirstFirst 1234 ... LastLast
Results 11 to 20 of 65
This is a discussion on Using Salesforce Outbound SOAP Messages with PHP within the Salesforce PHP Tutorials forums, part of the Salesforce category; I have corrected this code to handle the one to many relationship
  1. #11
    mike's Avatar
    mike is offline Administrator
    Join Date
    May 2007
    Location
    Wylie, Texas
    Posts
    607
    Blog Entries
    16
    I have corrected this code to handle the one to many relationship on outbound messages from Salesforce. I will post a generic version of the code sometime tomorrow

  2. #12
    mike's Avatar
    mike is offline Administrator
    Join Date
    May 2007
    Location
    Wylie, Texas
    Posts
    607
    Blog Entries
    16
    When I first started working with outbound messaging in Salesforce, I was ecstatic that we could perform various actions based on a work flow rule, such as if a field was updated to a certain value (example: Won) on a custom object, we were able to create data in a new custom object that allows us track Design Win's.

    Salesforce assigns an "ID" to each outbound message, to each Id of the object that is being used to send out the outbound message. I always thought that it was a 1 to 1 relationship, as I stated in an earlier post. This is not the case. There is a one to many relationship, which now has to be taken into consideration when writing the code to process your data coming in from Salesforce.

    The following where the problem is, in the function PARSENOTIFICATION:

    PHP Code:
    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 
    The function above only allows for one record to process, not many! so if you saw the incoming example message, you will see what I mean by the 1 to many relationship.

    I rewrote the function to process all of the incoming records and loop through to get all the data.

    Here is the rewritten function:

    PHP Code:
    function parseNotification($domDoc)
    {
        
    // Parse Notification parameters into result array

        
        
    $result = array("OrganizationId" => "","ActionId" => "","SessionId" => "","EnterpriseUrl" => "","PartnerUrl" => "","sObject" => null,"MapsRecords" => array());

        
    $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();
        
    $count 0;
        
    $tempMapRecord = array();
        foreach (
    $sObjectNodes as $node)
        {


            if (
    $node->localName == "Id")
            {
                if (
    $count 0)
                {
                    
    $result["MapsRecords"][] = $tempMapRecord;
                    
    $tempMapRecord = array();
                    
                }
                
    $tempMapRecord[$node->localName] = $node->textContent;
            }
            else
            {
                
    $tempMapRecord[$node->localName] = $node->textContent;
            }

            
    $count++;

        }

        
    // Finish last item
        
    $result["MapsRecords"][] = $tempMapRecord;
        
        return 
    $result;
    // end parseNotification 
    So you would get the data back with use like this:

    PHP Code:
    $resultArray parseNotification($dom);
    foreach (
    $resultArray['MapsRecords'] as $dwin_data)
    {
           
    //now you have an array as $dwin_data and you can use the
          //data as you need to for updates or calls back to salesforce
         //whatever you need to do is here

    When we create our Design Win custom object based on the outbound SOAP message, we do the following inside the foreach() loop:

    1. Query the Opportunity Object to get information needed for the Custom Object
    2. Query the Account Object to get information needed for the Custom Object
    3. Query the PriceBookEntry Object to get information needed for the Custom Object
    4. Query the User Object to get information needed for the Custom Object
    5. Build an array with all the required data
    6. perform a CREATE back to Salesforce to insert the new data into a new record within our custom object.
    7. Add a link back to the OpportunityLineItem for the new record that was created on the Design Win Object

    It works perfectly!! Try the new function out and let me know if you have any issues with it.

    ~Mike

  3. #13
    toddz is offline Junior Member
    Join Date
    Aug 2008
    Posts
    5

    php / wsdl help?

    Hi. Apologies in advance for my newbieness. And thank you so much for this thread.. this is exactly what I'm trying to setup for my company. But i'm having trouble putting all the pieces together (and i know nothing about soap). So i'm hoping for a more complete picture of how to setup the files on my server.

    I'm pretty sure my Outbound Messages are setup correctly within SF:
    - i setup an Outbound Message, specified an Endpoint URL, and downloaded the wsdl.
    - i setup a Workflow Rule, which finds something to send, which i can see in the queue (Administration Setup > Monitoring > Outbound Messages).


    But i know i don't have things setup correctly on my server yet, so the attempted send fails.
    The Queue shows:
    Delivery Failure Reason "org.xml.sax.SAXException: Bad envelope tag: br".

    And an error_log file is created on my server which says:
    Warning: DOMDocument::loadXML() [domdocument.loadxml]: Empty string supplied as input in /home/xxx/html/dev/sf/outboundmsg/index.php on line 16
    Fatal error: Call to a member function getAttribute() on a non-object in /home/xxx/html/dev/sf/outboundmsg/index.php on line 61


    i'm unclear how to set things up on my server:
    - i copied php code from this thread but don't understand how it all goes together in the file at my endpoint url. Any chance you could provide a complete php file?
    - i replaced the parseNotification function with the update, but i'm unclear where to put the $resultArray = parseNotification($dom); foreach .
    - where do i put the wsdl.xml file that i downloaded from SF?
    - how/where do i point to the wsdl? Is there a config var somewhere that i missed?
    - what to do with the Binding section (commented) in the wsdl from SF.
    - any other editing/config of the php or wsdl that i need to do? Or additional code or files that i'm missing?

    Also, one of the thread messages gave some php that included this:
    /* Handles SFDC Outbound Message notification.*/
    require_once ('../includes/salesforce_login.php');
    but i'm not clear what that's for, or what exactly goes in that file.

    I tried to figure it out from the SF help docs, but still couldn't find a simple straight-forward guide. Any help would be GREATLY appreciated.

    Thanks in advance,
    Todd

  4. #14
    mike's Avatar
    mike is offline Administrator
    Join Date
    May 2007
    Location
    Wylie, Texas
    Posts
    607
    Blog Entries
    16
    Quote Originally Posted by toddz View Post
    Hi. Apologies in advance for my newbieness. And thank you so much for this thread.. this is exactly what I'm trying to setup for my company. But i'm having trouble putting all the pieces together (and i know nothing about soap). So i'm hoping for a more complete picture of how to setup the files on my server.

    I'm pretty sure my Outbound Messages are setup correctly within SF:
    - i setup an Outbound Message, specified an Endpoint URL, and downloaded the wsdl.
    - i setup a Workflow Rule, which finds something to send, which i can see in the queue (Administration Setup > Monitoring > Outbound Messages).


    But i know i don't have things setup correctly on my server yet, so the attempted send fails.
    The Queue shows:
    Delivery Failure Reason "org.xml.sax.SAXException: Bad envelope tag: br".

    And an error_log file is created on my server which says:
    Warning: DOMDocument::loadXML() [domdocument.loadxml]: Empty string supplied as input in /home/xxx/html/dev/sf/outboundmsg/index.php on line 16
    Fatal error: Call to a member function getAttribute() on a non-object in /home/xxx/html/dev/sf/outboundmsg/index.php on line 61


    i'm unclear how to set things up on my server:
    - i copied php code from this thread but don't understand how it all goes together in the file at my endpoint url. Any chance you could provide a complete php file?
    - i replaced the parseNotification function with the update, but i'm unclear where to put the $resultArray = parseNotification($dom); foreach .
    - where do i put the wsdl.xml file that i downloaded from SF?
    - how/where do i point to the wsdl? Is there a config var somewhere that i missed?
    - what to do with the Binding section (commented) in the wsdl from SF.
    - any other editing/config of the php or wsdl that i need to do? Or additional code or files that i'm missing?

    Also, one of the thread messages gave some php that included this:
    /* Handles SFDC Outbound Message notification.*/
    require_once ('../includes/salesforce_login.php');
    but i'm not clear what that's for, or what exactly goes in that file.

    I tried to figure it out from the SF help docs, but still couldn't find a simple straight-forward guide. Any help would be GREATLY appreciated.

    Thanks in advance,
    Todd
    Todd I am going to try and break this post down to see if I can answer it in parts

    So there may be multiple posts to answer all your questions and I will try and help you as much as I can

    First have you tried to create a script that just performs a log in to Salesforce to make sure it works?

    When you download the phptoolkit, there is really only one relevant folder that is needed. the "/soapclient" folder

    all the other folders are just tutorials and such.


    when I develop apps, I always create an "/includes" folder for all my common scripts like the soapclient and that login script that you said you did not know what it was

    The login script is a small script that was written so I can just include that and it takes care of my login so all I have to do is a

    PHP Code:
    require_once('./includes/salesforce_login_script.php'
    Here is that script, so you can use it

    PHP Code:
    <?php

    // change these paths to your fully qualified paths for each script to include
    require_once ('/users/msimonds/public_html/includes/soapclient/SforcePartnerClient.php');
    require_once (
    '/users/msimonds/public_html/includes/soapclient/SforceHeaderOptions.php');

    // Login to salesforce.com
    $login "username";
    $password "password";

    // change this paths to your fully qualified paths for the script to include
    $wsdl "/users/msimonds/public_html/includes/soapclient/partner.wsdl.xml";

    $client = new SforcePartnerClient();
    $client->createConnection($wsdl);
    try
    {
        
    $loginResult $client->login($login$password);
        if (
    $loginResult->passwordExpired)
        {
            
    $client null;
        }
    }
    catch (
    exception $e)
    {
        
    $client null;
    }
    ?>
    You need to make sure you are getting a connection to salesforce and that you can login

    Hope that helps, once you get that part done, I will continue to help you get this setup

    ~Mike

  5. #15
    toddz is offline Junior Member
    Join Date
    Aug 2008
    Posts
    5
    Wow, thanks Mike.. tremendous help so far.

    I now have SF triggering an OutboundMsg, which is received at my EndpointURL (index.php), which writes some xml to "soap.xml".

    Here's my server so far:
    /dev/sf/outboundmsg/index.php (code from this thread)
    /dev/sf/outboundmsg/my_wsdl.xml (from my SF OutboundMsg setup)
    /dev/sf/outboundmsg/includes/soapclient/ (from phptoolkit-11_0b)
    /dev/sf/outboundmsg/includes/salesforce_login_script.php (with my paths and login)

    I'm ready for the next step!

    I assume i need to edit index.php?
    And do something with my custom WSDL from SF?

    Thanks again. This is very exciting.
    Todd

  6. #16
    mike's Avatar
    mike is offline Administrator
    Join Date
    May 2007
    Location
    Wylie, Texas
    Posts
    607
    Blog Entries
    16

    Talking Hope this works

    Quote Originally Posted by toddz View Post
    Wow, thanks Mike.. tremendous help so far.

    I now have SF triggering an OutboundMsg, which is received at my EndpointURL (index.php), which writes some xml to "soap.xml".

    Here's my server so far:
    /dev/sf/outboundmsg/index.php (code from this thread)
    /dev/sf/outboundmsg/my_wsdl.xml (from my SF OutboundMsg setup)
    /dev/sf/outboundmsg/includes/soapclient/ (from phptoolkit-11_0b)
    /dev/sf/outboundmsg/includes/salesforce_login_script.php (with my paths and login)

    I'm ready for the next step!

    I assume i need to edit index.php?
    And do something with my custom WSDL from SF?

    Thanks again. This is very exciting.
    Todd

    The following code could replace your index.php and be used to see if you are at least getting the data in an email

    look at this part of the code and make sure you change the email address that I have clearly marked in the comments


    PHP Code:
    <?php
    error_reporting
    (0);



    $data fopen('php://input','rb');

    $content stream_get_contents($data);

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

    //login script to salesforce for the $client variable ***change this path
    require_once ('/users/msimonds/public_html/includes/sfdc.inc');

    // setup an array for the data coming in from the SOAP message
    $dwin_data = array();

    $dom = new DOMDocument();
    $dom->loadXML($content);
    $resultArray parseNotification($dom);
    unset(
    $resultArray['sObject']);




    // Data from SOAP message.
    /***************************************************
    * This is where you do all your coding             *
    * and process the incomingin record as             *
    * need.  use the code:                             *
    * $temp = '<pre>' . print_r($var,true) . '</pre>'; * 
    * mail('youremail@address.com', 'Suject', $temp);  *     
    *                                                  *
    *  To test to make sure you are getting the        *
    *  data in an email, change the email address      *
    ****************************************************/
    foreach ($resultArray['MapsRecords'] as $dwin_data)
    {
        
        
    //make sure you are getting the email with the data in 
        //a print_r and then we can go from there
        
    $temp '<pre>' print_r($var,true) . '</pre>';  
        
    mail('youremail@address.com''Suject'$temp);
        
    }


    //clean all the data and then exit
    unset($client);
    unset(
    $dwin_data);
    unset(
    $dwin_create);
    unset(
    $records);
    exit;



    //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,"MapsRecords" => array());

        
    $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();
        
    $count 0;
        
    $tempMapRecord = array();
        foreach (
    $sObjectNodes as $node)
        {
            if (
    $node->localName == "Id")
            {
                if (
    $count 0)
                {
                    
    $result["MapsRecords"][] = $tempMapRecord;
                    
    $tempMapRecord = array();
                }
                
    $tempMapRecord[$node->localName] = $node->textContent;
            }
            else
            {
                
    $tempMapRecord[$node->localName] = $node->textContent;
            }
            
    $count++;
        }

        
    // Finish last item
        
    $result["MapsRecords"][] = $tempMapRecord;

        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>'
    ;
    }


    //this is the funciton to query salesforce objects to gather data
    //from different fields coming in from the SOAP message
    function get_records(&$connection,&$query)
    {
        
    $queryOptions = new QueryOptions(2000);

        
    $response = new QueryResult($connection->query($query));
        
    // if the size is zero, where done
        
    if ($response->size 0)
        {
            
    $products $response->records;
            
    // Cycles through additional responses if the number of records
            // exceeds the batch size
            
    while (!$response->done)
            {
                
    set_time_limit(100);
                
    $response $connection->queryMore($response->queryLocator);
                
    $products array_merge($products,$response->records);
            }
        }
        return 
    $products;
    }

    ?>
    this should be the next step

    ~Mike

  7. #17
    toddz is offline Junior Member
    Join Date
    Aug 2008
    Posts
    5
    Hi Mike, thanks for the continued help here.
    I am getting the email now, but it does not have the soap data yet. The email only shows:
    Code:
     <pre></pre>
    I'm not clear how $var is defined in..
    Code:
    foreach ($resultArray['MapsRecords'] as $dwin_data)
    { 
        $temp = '<pre>' . print_r($var,true) . '</pre>';  
        mail('my@email.com', 'soap from sf', $temp); 
    }
    Do i need to change something in there?

    And to verify that my OutboundMessage does contain data, i set index.php to log to a local file (soap.xml) again (instead of sending an email), and i still get the full soap xml, including fields and values data.

    sorry if i'm missing something here. thanks in advance.
    todd

  8. #18
    mike's Avatar
    mike is offline Administrator
    Join Date
    May 2007
    Location
    Wylie, Texas
    Posts
    607
    Blog Entries
    16
    Crap! My Bad

    PHP Code:
    foreach ($resultArray['MapsRecords'] as $dwin_data)
    {
        
        
    //make sure you are getting the email with the data in 
        //a print_r and then we can go from there
        
    $temp '<pre>' print_r($var,true) . '</pre>';  
        
    mail('youremail@address.com''Suject'$temp);
        


    SHOULD BE


    PHP Code:
    foreach ($resultArray['MapsRecords'] as $dwin_data)
    {
        
        
    //make sure you are getting the email with the data in 
        //a print_r and then we can go from there
        
    $temp '<pre>' print_r($dwin_data,true) . '</pre>';  
        
    mail('youremail@address.com''Suject'$temp);
        


    that way the $resultArray becomes the $dwin_data array in the foreach loop and you should get an email that has each element in the array with its value


    Sorry about that and let me know if it works

    ~Mike

  9. #19
    toddz is offline Junior Member
    Join Date
    Aug 2008
    Posts
    5
    BINGO!
    The email message contained the array and all its key => values.
    I also had it just write the same thing to a local log file.

    I suppose now i can get to any element of the array, like this..
    $dwin_data['MySFfieldName']
    and plug them into a database or something.

    But of course i defer to you.. what do you do next?
    And, what about the custom WSDL file (downloaded from my SF OutboundMsg setup)? That's not even used yet, right?

    thanks..
    todd

  10. #20
    mike's Avatar
    mike is offline Administrator
    Join Date
    May 2007
    Location
    Wylie, Texas
    Posts
    607
    Blog Entries
    16
    If you talking about the custom WSDL file that you downloaded from that outbound message, honestly you do not really need it unless you were going to access that via some APEX code or connect using PHP to that WSDL

    That just gives you a list of classes or functions you can use and data access points.


    Since you have the data now in an array, $dwin_data. You can do almost whatever you want to with it

    • Stick it in a database
    • Send it back to Salesforce into a custom Object
    • Email it to someone
    • Stick it in a CSV

    I mean it is up to you

    ALSO

    I only did the initial logging to a file to make sure that I was getting the messages.

    You can turn that part off

    Make sure that your outbound message is getting cleared out of the queue in Salesforce. I think it is Setup > Monitoring > Outbound message queue or something like that.

    Let me know if you have any other questions and I am glad that you got it to work

    ~Mike

+ Reply to Thread
Page 2 of 7 FirstFirst 1234 ... LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts

SEO by vBSEO 3.5.2