Skip to content

Instantly share code, notes, and snippets.

@shawn-crigger
Last active January 1, 2018 07:37
Show Gist options
  • Save shawn-crigger/53c431aabf81f8d9e12822302da977af to your computer and use it in GitHub Desktop.
Save shawn-crigger/53c431aabf81f8d9e12822302da977af to your computer and use it in GitHub Desktop.
Salesforce SOAP API Outbound Message Listener
<?php
/**
* Salesforce Workflow Outboud message reciever sample in PHP
*
* requires: php-soap extension
*
* At 1st you should download WSDL of the message and put it besides this script.
*/
//ini_set("soap.wsdl_cache_enabled", "0"); // clean WSDL for develop
ini_set('display_errors', 1);
/**
* Simple method to write string to a file
*
* @param string $log The log
*/
function log_writeln( $log = '' )
{
$success = file_put_contents(__DIR__ . '/log/' . @date('Y-m-d') . '.log', $log . "\n", FILE_APPEND);
}
/**
* Salesforce Outbound Response type
*/
class Response
{
public $Ack;
function __construct($success)
{
$this->Ack = $success;
}
public static function success()
{
return new static(true);
}
public static function fail()
{
return new static(false);
}
}
// ------------------------------------------------------------------------
/**
* Simple wrapper for success wrapper
*/
class WSDL_Response {
/**
* Outputs XML response of true or false to SOAP server
* @static
* @param string $tf
* @return VOID
*/
public static function respond( $response = true )
{
$response = ( true === $response ) ? 'true' : 'false';
$ACK = <<<ACK
<?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>{$response}</Ack>
</notifications>
</soapenv:Body>
</soapenv:Envelope>
ACK;
echo trim($ACK);
}
}
// ------------------------------------------------------------------------
/**
* Main class that listens for the server response and processes the data
*
*/
class Listener {
/**
* WSDL file
*
* @var string
*/
private $_wsdl = __DIR__ . '/' . 'wfoutbound.wsdl';
/**
* MySQL holder
* @var object
*/
private $_mysql = NULL;
/**
* MySQL config
* @var array
*/
private $_config = array(
'user' => '',
'pass' => '',
'db' => '',
'table' => 'opportunity',
);
/**
* SOAP server holder
* @var SOAPServer
*/
private $_server;
public function __construct($value='')
{
//$this->_wsdl = 'http://35.197.164.194/s6.wsdl';
$options = array( 'trace' => 1, 'exceptions' => 1, 'soap_version' => SOAP_1_2 );
try {
$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
$this->_server = new SOAPServer( $this->_wsdl, $options );
// xml_parser( $this->_wsdl, $this->_server );
$this->_server->setClass( 'Listener' );
$request = file_get_contents('php://input');
// start buffer
ob_start();
$this->_server->handle( $request );
// collect response from buffer
$response = ob_get_clean();
// $server = new SoapServer(null, array('uri' => 'https://website.com/services/SFService.php'));
}
catch(SOAPFault $e) {
error_log(print_r($e->getMessage(),1).' '.__FILE__.':'.__LINE__,0);
}
$this->_process( $response );
// dump($resp);
return $response;
}
// ------------------------------------------------------------------------
private function _connect_mysql()
{
$this->_mysql = mysqli_connect( $this->_config['db'], $this->_config['user'], $this->_config['pass'] );
// Check connection
if (!$this->_mysql)
{
die("Connection failed: " . mysqli_connect_error() );
}
return true;
}
// ------------------------------------------------------------------------
/**
* Handles processing the response object
*
* @param object $data Response from the WSDL server
*/
private function _process( $data )
{
log_writeln( $data );
// test line to verify response is as expected.
if ( ! isset( $data->Notification ) ) return false;
log_writeln( '$data->Notification is set, need to loop then' );
$array = $data->Notification;
// There should be the following object values inside of $row->sObject
// $row->Id
// $row->sObject->Notes__c
// $row->sObject->Telemarketer__c
// Will write the SQL to check against $row->Id, if exists UPDATE else CREATE
// temp response log, after a log has been run, the SQL query can be wrote.
foreach ($array as $row)
{
log_writeln( 'NOTIFICATION ID = ' . $row->Id );
foreach ($row->sObject as $key => $value)
{
log_writeln( 'KEY = ' . $key );
log_writeln( 'VALUE = ' . $value );
}
}
}
// ------------------------------------------------------------------------
/**
* Handles MySQL INSERT of notification
* @access private
* @param array $values Array containing Id, telemarketer and notes
*/
private function _create( $values )
{
$table = $this->_config['table'];
$db = $this->_config['db'];
$now = date('Y-m-d H:i:s');
$close = $now;
$amount = '0.00';
$probability = '0.00';
$expected = '0.00';
$isClosed = 0;
$isWon = 0;
$recordType = 0;
$id = mysql_real_escape_string( $values['Id'] );
$telemarketer= mysql_real_escape_string( $values['telemarketer'] );
$notes = mysql_real_escape_string( $values['notes'] );
$sql = "INSERT INTO `{$db}`.`{$table}`
(`ID`, `RecordTypeId`, `Name`, `StageName`, `Amount`, `Probability`, `ExpectedRevenue`,
`CloseDate`, `IsClosed`, `IsWon`, `CreateDate`, `LastModifiedDate`, `LastActivityDate`,
`LastViewedDate`, `ActivityStage`, `Action`, `Phone`, `FirstName`, `LastName`, `Email`,
`Source`, `Telemarketer`, `Notes`)
VALUES
('{$id}', '{$recordType}', '', '', '{$amount}', '{$probability}', '{$expected}', '{$close}', '{$isClosed}', '{$isWon}', '{$now}', '{$now}', '{$now}', '{$now}', '', '', '', '', '', '', '', '{$telemarketer}', '{$notes}' );
";
$result = mysqli_query( $this->_mysql, $sql );
}
// ------------------------------------------------------------------------
/**
* Handles MySQL UPDATE of notification
* @access private
* @param array $values Array containing Id, telemarketer and notes
*/
private function _update( $values )
{
$table = $this->_config['table'];
$db = $this->_config['db'];
$id = mysql_real_escape_string( $values['Id'] );
$telemarketer = mysql_real_escape_string( $values['telemarketer'] );
$notes = mysql_real_escape_string( $values['notes'] );
$sql = "UPDATE `{$db}`.`{$table}` SET
`Telemarketer` = '{$telemarketer}',
`Notes` = '{$notes}'
WHERE `{$table}`.`ID` = '{$id}';";
$result = mysqli_query( $this->_mysql, $sql );
}
// ------------------------------------------------------------------------
/**
* Queries database from record with ID returns true/false if record exists
* @access private
* @param string $id Notification ID
* @return boolean
*/
private function _check_record( $id )
{
$table = $this->_config['table'];
$db = $this->_config['db'];
$id = mysql_real_escape_string( $id );
$sql = "SELECT `ID` FROM `{$db}`.`{$table}` WHERE 1 = 1 AND `ID` = '{$id}' ";
$result = mysqli_query( $this->_mysql, $sql );
if ( mysqli_num_rows( $result ) > 0 ) return TRUE;
return FALSE;
}
// ------------------------------------------------------------------------
/**
* Notification request handler
*/
public function notifications($args=null)
{
log_writeln(date('Y-m-d H:i:s'));
log_writeln(print_r($args, true));
// Success response
//echo WSDL_Response(true);
$response = '<Ack>true</Ack>';
$response = new SoapVar($response,XSD_ANYXML);
return $response;
return Response::success();
}
// ------------------------------------------------------------------------
}
// ------------------------------------------------------------------------
//require('./helpers.php');
$notification = new Listener();
// log_writeln($resp);
//echo $resp;
<?xml version="1.0" encoding="UTF-8"?>
<!--
Salesforce.com Outbound Notification Web Services API Version 1.0
Generated on 2017-12-31 06:17:19 +0000.
Copyright 2005-2017 Salesforce.com, Inc.
All Rights Reserved
-->
<definitions targetNamespace="http://soap.sforce.com/2005/09/outbound"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://soap.sforce.com/2005/09/outbound"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ent="urn:enterprise.soap.sforce.com"
xmlns:ens="urn:sobject.enterprise.soap.sforce.com">
<types>
<schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:enterprise.soap.sforce.com">
<!-- Our simple ID Type -->
<simpleType name="ID">
<restriction base="xsd:string">
<length value="18"/>
<pattern value='[a-zA-Z0-9]{18}'/>
</restriction>
</simpleType>
</schema>
<schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:sobject.enterprise.soap.sforce.com">
<import namespace="urn:enterprise.soap.sforce.com" />
<!-- Base sObject (abstract) -->
<complexType name="sObject">
<sequence>
<element name="fieldsToNull" type="xsd:string" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<element name="Id" type="ent:ID" nillable="true" />
</sequence>
</complexType>
<complexType name="AggregateResult">
<complexContent>
<extension base="ens:sObject">
<sequence>
<any namespace="##targetNamespace" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="Call_Attempt__c">
<complexContent>
<extension base="ens:sObject">
<sequence>
<element name="Notes__c" nillable="true" minOccurs="0" type="xsd:string"/>
<element name="Telemarketer__c" nillable="true" minOccurs="0" type="xsd:string"/>
</sequence>
</extension>
</complexContent>
</complexType>
</schema>
<schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://soap.sforce.com/2005/09/outbound">
<import namespace="urn:enterprise.soap.sforce.com" />
<import namespace="urn:sobject.enterprise.soap.sforce.com" />
<element name="notifications">
<complexType>
<sequence>
<element name="OrganizationId" type="ent:ID" />
<element name="ActionId" type="ent:ID" />
<element name="SessionId" type="xsd:string" nillable="true" />
<element name="EnterpriseUrl" type="xsd:string" />
<element name="PartnerUrl" type="xsd:string" />
<element name="Notification" maxOccurs="100" type="tns:Call_Attempt__cNotification" />
</sequence>
</complexType>
</element>
<complexType name="Call_Attempt__cNotification">
<sequence>
<element name="Id" type="ent:ID" />
<element name="sObject" type="ens:Call_Attempt__c" />
</sequence>
</complexType>
<element name="notificationsResponse">
<complexType>
<sequence>
<element name="Ack" type="xsd:boolean" />
</sequence>
</complexType>
</element>
</schema>
</types>
<!-- Method Messages -->
<message name="notificationsRequest">
<part element="tns:notifications" name="request"/>
</message>
<message name="notificationsResponse">
<part element="tns:notificationsResponse" name="response"/>
</message>
<!-- PortType -->
<portType name="NotificationPort">
<operation name="notifications">
<documentation>Process a number of notifications.</documentation>
<input message="tns:notificationsRequest"/>
<output message="tns:notificationsResponse"/>
</operation>
</portType>
<!-- Binding
You need to write a service that implements this binding to receive the notifications
-->
<binding name="NotificationBinding" type="tns:NotificationPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="notifications">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<!-- Service Endpoint -->
<service name="NotificationService">
<documentation>Notification Service Implementation</documentation>
<port binding="tns:NotificationBinding" name="Notification">
<soap:address location="http://35.197.164.194/s6.wsdl"/>
</port>
</service>
</definitions>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment