The CreatorCon Call for Content is officially open! Get started here.

SOAP PHP Implementation

sherman_1206
Tera Contributor

So after a lot of SOAP trial and error and a lack of examples or any documentation on using Service now soap web service with PHP I decided to implement a php class for using Service Now SOAP Web Service. The implementation is thus far only as robust as I have needed it to be but feel free to comment or add to it... I think this could be a good thing going forward.

Currently supported functionality:
-construct new ServiceNowSoapClient

-setLocation($location) - a way to change the web service link you are using if you wish to query some other cmdb_ci table

-listAvailableFunctions - a fun extra function to dump a list of functions available at the respective web service link

- getRecords($query) - accepts an array to query the web service for, this can be one of two things:
- encoded query of the form array("__encoded_query" => "");
- regular query of form array("param1" => "value1", "param2" => "value2", ... )

get($sys_id) - accepts an id of a service now record at the respective instance and returns this object

Next implementation:

-getKeys function - although I have yet to need this one although I suppose you could call getKeys to get a list of system ids and then do something like foreach($keys as $key){ // call SoapServiceNowClient->get($key) }
that way you could call getKeys to delimit your result set and then use get to get each record individually although I think getRecords would be easier for this purpose

-insert

-update

-delete

Although as far as those go, thus far the only application we have for SOAP is to produce text view of service now information, therefore, I will get to these when I do but feel free to contact me if you want to discuss these and I can help you implement them as I do not see them as being difficult at all.

Now for the best part the code!



<?php
/**
*Class: SeviceNowSoapClient
*Description: a wrapper class for php SoapClient to ease the usage of service
*now soap web services
*Date: 06.25.2010
*Author: Chris Sherman
*License: none, use it as you wish but do give credit to those who help 😉
*/
class ServiceNowSoapClient{
private $client, $instance, $login, $password;

/**
*location must be to a WSDL service location within service-now.com
*ie. https://demo.service-now.com/cmdb_ci_service.do?WSDL
*login and password must be a service-now.com user with SOAP access added to its account
*/
public function __construct($location, $login, $password){
$this->setLogin($login);
$this->setPassword($password);
$this->location = $location;

$this->client = new soapclient($this->location,$this->getAuthorization());

}

/**
*Function: getRecords($query)
*Purpose: Implements the ServiceNow Soap GetRecords method. The idea is that
*we accept an array containing the query and always return back an array.
*This method is what makes this class so great. Service Now Server
*can return to to soap client multiple types,
*-either an array of record objects when multiple
*objects are in the result set
*-a record object when one item is in result set
*-a record object which is empty when no results are returned
*Instead of handling that mess with all soap queries this function
*handles it for you by determining if the result is an array, or
*or not and it will always return an array. The array can be empty,
*for no results, or have some number of recorc objects in it. 🙂
*param: array, the query for soap web service
*return: array, array containing record objects or an empty array for no results
*/
public function getRecords($query){
$result = $this->client->__soapCall('getRecords',array('GetRecords' => $query));
$returnResult = array();

if(isset($result)){
if(isset($result->getRecordsResult) and is_array($result->getRecordsResult)){
$returnResult = $result->getRecordsResult;
}else{
$returnResult = array($result->getRecordsResult);
}
}

return $returnResult;
}

/**
*Function: set login
*Purpose: Helper function you will not need as of now.
*sets $this->login = $login
*param: string, the login for this service now soap web service
*return: void
*/
public function setLogin($login){
$this->login = $login;
}
/**
*Function: setPassword($password)
*Purpose: Helper function you will not need as of now.
*sets $this->password = $password
*param: string, the password for this soap web service
*return: void
*/
public function setPassword($password){
$this->password = $password;
}

//sets a new end point for soap client
//SoapClient::__setLocation throws error on the call and
//for time being I will just construct a new soap client
/**
*Function: setLocation($location)
*Purpose: Updates the location to the WSDL SOAP Service
*Now web service
*As of now method constructs a new SoapClient with updated
*location as I was having problems with using SoapClient->__setLocation
*I attribute this to the WSDL but thats for another day.
*param: string, the location of the new web service
*return: void
*/
public function setLocation($location){
//$this->client->__setLocation($location);
$this->location = $location;
$this->client = new soapclient($this->location,$this->getAuthorization());
}
/**
*Function: getAuthorization()
*Purpose: Helper function you will not need as of now.
*Used when constructor constructs a new soap client or
*when set location is called. Creates the array to authenticate
*with the web service.
*param: null
*return: associative array, this.array('login' -> $this->login, 'password'->$this->password')
*/
public function getAuthorization(){
return array('login'=> $this->login, 'password' => $this->password);
}

//auxilary function to merely dump the list of available functions
//specific this.client.currentLocation
public function listAvailableFunctions(){
var_dump($this->client);
print_r($this->client->__getFunctions());
}

/**
*Function: getRecords($query)
*Purpose: Implements the ServiceNow Soap GetRecords method. The idea is that
*we accept an array containing the query and always return back an array.
*This method is what makes this class so great. Service Now Server
*can return to to soap client multiple types,
*-either an array of record objects when multiple
*objects are in the result set
*-a record object when one item is in result set
*-a record object which is empty when no results are returned
*Instead of handling that mess with all soap queries this function
*handles it for you by determining if the result is an array, or
*or not and it will always return an array. The array can be empty,
*for no results, or have some number of recorc objects in it. 🙂
*param: array, the query for soap web service
*return: array, array containing record objects or an empty array for no results
*/
public function getRecords($query){
$result = $this->client->__soapCall('getRecords',array('GetRecords' => $query));
$returnResult = array();

if(isset($result)){
if(isset($result->getRecordsResult) and is_array($result->getRecordsResult)){
$returnResult = $result->getRecordsResult;
}else{
$returnResult = array($result->getRecordsResult);
}
}

return $returnResult;
}
/**
*Fucntion: get($sys_id)
*@todo: finish implementation of get call
*/
public function get($sys_id){
echo $sys_id;
$result = $this->client->__soapCall('get',array('sys_id' => $sys_id));
var_dump($result);
}

/*
public function buildEncodedQuery(){

}
*/
}

?>

12 REPLIES 12

You need to specific your limits and make multiple requests.


This is a limitation on the servicenow side to prevent performance implications of querying tables with many records.

To obtain many records you can use a counter and make the same request multiple times incrementing your counter.

A simple python example:



from SOAPpy import SOAPProxy

#dynamic elements of SOAP endpoint construction
username, password, instance, gliderecord = 'user', 'pass', 'instance', 'table endpoint'
proxy = "https://%s:%s@%s.service-now.com/%s.do?SOAP" % (username, password, instance, gliderecord, )
namespace = 'http://www.glidesoft.com/'

server = SOAPProxy(proxy,namespace)
#limit record set?
start, end = 0, 249
response = server.getRecords(_order_by='number', __first_row=start, __last_row=end)

continue = True

while continue:
if not len(response):
continue = False
for r in response:
# process your records data here...
start += 250
end += 250
response = server.getRecords(_order_by='number', __first_row=start, __last_row=end)


I used python merely because I had an example quite handy but the above logic would translate to PHP fairly trivially. I hope this helps!


Hey again..Can I get an example of update stmt.

Shahid


You sure can, update is same as insert more or less. The one thing that is required if the sys_id parameter so Service Now when processing your soap message knows which record to update.



$updateRecord = array();
$updateRecord["sys_id"] = "12345678901234567890123456789012";
$updateRecord["short_description"] = "This is an updated short description";

//construct incident object
$i = new Incident();
$i->update( $updateRecord );



That should cover a basic update. One thing to note though is that you should inspect the WSDL to make sure you are passing all fields required. To determine which are required for incident you could navigate to http://.service-now.com/incident.do?WSDL and in that XML document look for the following line:



<xsd:element name="update">



Underneath this line you have elements and for each element there is an attribute "minOccurs". Lets look at an example:



//for simplicity I have removed many elements to keep this short

<xsd:element name="update">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="short_description" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="sla_due" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="state" type="xsd:integer"/>
<xsd:element maxOccurs="1" minOccurs="0" name="subcategory" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="1" name="sys_id" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="upon_approval" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="upon_reject" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>



As you can see in this situation for me to update the following are required: sys_id, and short_description.

Hope that helps!


sherman_1206
Tera Contributor

As of today I have begun to rework the entire Service Now Soap Interaction library I am constructing from the ground up! First off it will contain ServiceNowSoapClient, ServiceNowIncidentManager, ServiceNowIncident, ServiceNowUserManager, ServiceNowUser, ServiceNowChoiceList, ServiceNowEncodedQuery.

The ServiceNowSoapClient has been modified to strictly user static functions to perform its functionality. Additionally I have included all soap server interactions within try/catches and will return false for any soap call that has failed {get, getRecords, insert, update, etc...} This way you can simple check if the return is false to know.

Also, there is a static $instance at the top which defines the location to your service now instance. Do not worry about the final location such as incident.do?WSDL or sys_user.do?WSDL this will be provided within the function parameter list. The reason for this is that you are not instantiated this class, you are merely using it for ANY soap interactions and therefore want to provide the end point WSDL to your calls. This way you no longer need to instantiate a new ServiceNowSoapClient for all your WSDL end point locations you can just user a call such as ServiceNowSoapClient::getRecords("incident.do?WSDL",array('field'=>'value',...)); and it will get you what you want..

Here is the Soap Client, comments were removed to keep it short but please comment if you wish to further develop this or want some help with using it for your Service Now Soap interactions.

Next week when I finish coding the rest, I will include ServiceNowUserManager, ServiceNowUser, ServiceNowIncidentManager, ServiceNowIncident and anything else I finish coding.




<?php
/**
*Class: SeviceNowSoapClient
*Description: a wrapper class for php SoapClient to ease the usage of service
*now soap web services
*Date: 07.16.2010
*Author: Chris Sherman
*License: none, enjoy it 🙂
*
*
*/
class ServiceNowSoapClient{
public static $instance = 'https://osuitsmtest.service-now.com/';
public static $login='SOAPUSERNAME';
public static $password='PASSWORDFORSOAPUSER';


public static function getAuthorization(){
return array('login'=> self::$login, 'password' => self::$password);
}

//auxilary function to merely dump the list of available functions
//specific this.client.currentLocation
public static function listAvailableFunctions($WSDL){
try{
$client = new soapclient(self::$instance.$WSDL,self::getAuthorization());
$result = $client->__getFunctions();
foreach($result as $key=>$value){
echo $key.' -> '.$value.'
';
}
}catch(SoapFault $exception){
echo $exception;
}

}

public static function getRecords($WSDL, $query=array()){
$returnResult = array();
try{
$client = new soapclient(self::$instance.$WSDL,self::getAuthorization());
$result = $client->__soapCall('getRecords',array('GetRecords' => $query));

if(isset($result)){
if(isset($result->getRecordsResult)){
if(is_array($result->getRecordsResult)){
$returnResult = $result->getRecordsResult;
}else if(isset($result->getRecordsResult->name)){
$returnResult = array($result->getRecordsResult);
}
}
}//end if isset
return $returnResult;
}catch(SoapFault $exception){
//echo $exception;
return $returnResult;
}

}

public static function insert($WSDL, $query){
try{
$client = new soapclient(self::$instance.$WSDL,self::getAuthorization());
$result = $client->__soapCall('insert',array('insert' => $query));
return true;
}catch(SoapFault $exception){
//echo $exception;
return false;
}

}

public static function insertResponse($WSDL, $query=''){
try{
$client = new soapclient(self::$instance.$WSDL,self::getAuthorization());
$result = $client->__soapCall('insertResponse',array('insertResponse' => $query));
return true;
}catch(SoapFault $exception){
//echo $exception;
return false;
}

}

public static function update($WSDL, $query){
try{
$client = new soapclient(self::$instance.$WSDL,self::getAuthorization());
$result = $client->__soapCall('update',array('update' => $query));
return true;
}catch(SoapFault $exception){
//echo $exception
return false;
}
}
public function get($sys_id){
try{
$client = new soapclient(self::$instance.$WSDL,self::getAuthorization());
$result = $client->__soapCall('get', array('get'=> array('sys_id'=>$sys_id)));
return $result;
}catch(SoapFault $exception){
//echo $exception;
return false;
}
}
}

?>