2

I'm attempting to create a PHP app that access web service methods through SOAP API calls using the Force.com Toolkit. Currently this is working with REST calls, but as I clean up some things on this project it seems easier if this was available in SOAP.

On the APEX side I have a webservices defined like so:

webservice static myOutputs getSomeAccounts(myInputs inputs){
    // Do stuff to create an output
    return output;
}

Then on the PHP side I have my app defined like so:

class MyApp {

    protected $client

    function __construct(){
        # Standard connection based on documentation
        $sf_connector = new SalesforceConnector();
        # Return SforcePartnerClient object from ForceTK
        $this->client = $sf_connector->client; 

    }

    # Web service request   // DOESN'T WORK
    function webserviceTest(){
        $response = $this->client->getSomeAccounts($params);
        # getSomeAccounts() is not recognized by the client...
        # Hoping for something like $this->client->webservice('getSomeAccounts');
    }

    # Query test      // WORKS
    function query(){
        $query = "SELECT Id, FirstName, LastName, Phone from Contact LIMIT 10";
        $response = $this->client->query($query);
        $queryResult = new QueryResult($response);

        for ($queryResult->rewind(); $queryResult->pointer < $queryResult->size; $queryResult->next()) {
            $record = $queryResult->current();
            echo $record->Id.": ".$record->fields->FirstName." ".$record->fields->LastName." ".$record->fields->Phone."<br/>\n";
        }
    }
}

Is it not possible to do what I want through SOAP? Or is this just a limitation of the Force.com Toolkit? First time working with SOAP and feel like I'm grasping things fine just not sure how to make this request.

Thanks for the help

  • I don't think I've ever heard someone utter the phrase "This would be easier if I could use SOAP". Aside from needing to work with and manage OAuth, is there a particular reason why you want to avoid REST? JSON is a lot easier to handle than XML imo (and faster too, I believe), and making a REST call via cURL is dead simple most times. – Derek F Sep 14 '16 at 14:17
  • @DerekF - lol, I agree, but I'm working with a legacy project that used SOAP and uses OAuth, so until I understand the "whys" of the project I don't want to divert too much from what is in place – Xtremefaith Sep 16 '16 at 18:52
2

This is likely a limitation of how SOAP and the Force.com Toolkit work.

SOAP APIs work by defining a WSDL that describes all the allowed API calls along with their expected parameters and return types.

The Force.com Toolkit will be built upon the Partner API. This is generic API for doing CRUD type operations and checking dynamic metadata to see what objects and fields the connected org exposes.

What the Partner API doesn't do in it's WSDL is expose your custom getSomeAccounts Apex web service method. To consume that you will need to generate the WSDL for the parent Apex class and then interact with that in the appropriate way from PHP. What the appropriate way is for PHP I don't know.

You could probably use the Force.com Toolkit as a boiler plate for how to make the API call. The custom WSDL and the Partner API share many common types. E.g. you will be able to use the Session ID from the Partner API in the headers of your custom Apex web service.

2

In addition to Daniel's answer to "switch" WSDL in php the below is an example of:

  1. Login via the Partner/Enterprise WSDL
  2. Pass information to a Webservice WSDL generated from the Apex class in salesforce
  3. Execute a method in the web service

The key here is you need to login and then pass the session info to the other wsdl to make the call from that wsdl

<?php
define("USERNAME", "xxxxx");
define("PASSWORD", "xxxxx");
//define("SECURITY_TOKEN", "If Needed");

require_once ('soapclient/SforcePartnerClient.php'); //Use Enterprise instead of partner if needed
require_once ('soapclient/SforceHeaderOptions.php');

$mySforceConnection = new SforcePartnerClient(); //Use Enterprise instead of partner if needed
$mySforceConnection->createConnection("soapclient/partner.wsdl.xml"); //Use Enterprise instead of partner if needed
$loginResult = $mySforceConnection->login(USERNAME, PASSWORD);

//Get the Pod of the URL
$parsedURL = parse_url($mySforceConnection->getLocation());
//Define the properties to make the full URL
//**soapclient** is the directory where the WSDL is stored
define ("_SFDC_SERVER_", substr($parsedURL['host'],0,strpos($parsedURL['host'], '.')));  
define ("_WS_NAME_", "TChargentOperations");  
define ("_WS_WSDL_", "soapclient/" . _WS_NAME_ . ".wsdl.xml");  
define ("_WS_ENDPOINT_", 'https://' . _SFDC_SERVER_ . '.salesforce.com/services/wsdl/class/' . _WS_NAME_);  
//ChargentOrders/ is the namespace for the packaged classes
define ("_WS_NAMESPACE_", 'http://soap.sforce.com/schemas/class/ChargentOrders/' . _WS_NAME_);

//Echo the results to check
echo _SFDC_SERVER_."<br>";  
echo _WS_NAME_."<br>";  
echo _WS_WSDL_."<br>";  
echo _WS_ENDPOINT_."<br>";  
echo _WS_NAMESPACE_."<p>";

//Create a new Soap Client
$client = new SoapClient(_WS_WSDL_);
//Set the session Header properties
$sforce_header = new SoapHeader(_WS_NAMESPACE_, "SessionHeader", array("sessionId" => $mySforceConnection->getSessionId()));
$client->__setSoapHeaders(array($sforce_header));

    //Execute the applicable method. In this example it is the Authorization
    $wsParams=array('OrderId'=>'cxxxxxxxxxxxxxx'); //query for the id you need. For this example it is just hardcoded which will NOT work in your instance
    $response = $client->AuthorizeOrder_Click($wsParams);
    //$response = $client->VoidTransaction_Click(array('TransactionId'=>'cxxxxxxxxxxxxxx'));
    // dump the response to the browser
    print_r($response);
    echo '<br/>';
    print_r($response->result);
    echo '<br/>';
    //Get the resultant transaction ID
    $tranId = $response->result->TransactID;
    echo $tranId . "<br>";
    //Void the transaction immediatly as an example so we can run this again and again. (Can only have one authorization);
    $voidResponse = $client->VoidTransaction_Click(array('TransactionId'=>$tranId));
    echo '<br/>';
    print_r($voidResponse);
?>

I am by no means a php whiz so there is most likely a better way to do this however this does show what is needed to use soap / php to execute web service methods defined in your apex classes

  • Are you saying to create a new SoapClient() rather than using SforceSoapClient from ForceTK which extends SoapClient? At that point should my app just have its own client (i.e. MyAppSoapClient), which is pre-configured to use the WSDL and heads that it needs? Also can you explain the SoapHeader? Currently ForceTK has methods for using setEndpoint() and setSessionHeader() – Xtremefaith Sep 15 '16 at 0:02
  • @Xtremefaith - i do not use the toolkit so not sure how to answer other than Webservice classes have their own WSDL and you need to switch to that WSDL in your code in order to execute those methods – Eric Sep 15 '16 at 0:03
  • @Xtremefaith - I do not think you need to write your own client as the ones mentioned in my php are robust enough. Even if you write your own client you will still have to switch wsdls to execute the methods from the web service class. I guess I do use the toolkit and did not realize it :) – Eric Sep 15 '16 at 0:27
  • I guess to your example of $response = $client->AuthorizeOrder_Click($wsParams); does the PHP client need to define AuthorizeOrder_Click() which maps to the WSDL or is simply having the correct WSDL (containing <xsd:element name="AuthorizeOrder_Click">) suppose to handle that? – Xtremefaith Sep 16 '16 at 18:39
  • @Xtremefaith - The AuthorizeOrder_Click is a web service method in my apex class which is in the WSDL I switched to in the PHP code – Eric Sep 16 '16 at 18:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.