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

sherman_1206
Tera Contributor

I have updated the soap implementation with a few extra functions you might enjoy seeing.

Let me know if anyone has any questions regarding a PHP implementation for Service Now SOAP interactions. I have done a lot more then this but this is the base Class I am using for all of my interactions. Currently, I have done a few things: first implemented an external web interface for Incident management on a per user basis along with pulling some data from service now to display to user.

The result: the user goes to service-now instance content management page which I have coded in service now to be a dynamic login form and upon succesful authentication to service-now the user is redirected to my external page if the user does not have a specific role in our case "itil". At that point this class handles most of teh work along with some functions I have coded to use this class pretty extensively.

Enjoy!



<?php
/**
*Class: SeviceNowSoapClient
*Description: a wrapper class for php SoapClient to ease the usage of service
*now soap web services
*Date: 07.08.2010
*Author: Chris Sherman
*License: none, enjoy it 🙂
*
*
*/
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: 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(){
$result = $this->client->__getFunctions();
foreach($result as $key=>$value){
echo $key.' -> '.$value.'
';
}
}

/**
*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)){
if(is_array($result->getRecordsResult)){
$returnResult = $result->getRecordsResult;
}else if(isset($result->getRecordsResult->name)){
$returnResult = array($result->getRecordsResult);
}
}
}
return $returnResult;
}


/**
*function insert($query)
*inserts a record into service now.
*
*@param array associative field -> value pairs
*/
public function insert($query){
$result = $this->client->__soapCall('insert',array('insert' => $query));
}


/**
*function: update($query)
*Updates a specific record in service now, the record is sepcific
*to constructors location argument.
*
*@param array - associative array of field -> value pairs
*@requires adhering to WSDL of specific location with at least
*the min requirements.
*/
public function update($query){
$result = $this->client->__soapCall('update',array('update' => $query));
}
/**
*Function: get($sys_id)
*Gets a specific record by its system id. Specific to a given
*WSDL defined via constructor. IE. http://service-now.com/incident.do?WSDL
*specified as $location param to cnostructor then making call to $this::get($sys_id)
*returns an incident with given sys id.
*@param: system id
*@todo:
*/
public function get($sys_id){
$result = $this->client->__soapCall('get', array('get'=> array('sys_id'=>$sys_id)));
return $result;
}


}

?>


Thanks for the class. I can do most of my task with this class. Need a small help. I want to get records which uses datate range like

closed_atBETWEENjavascript%3Ags.dateGenerate('$resolveDateStart')%40javascript%3Ags.dateGenerate('$resolveDateEnd')

How do I pass this in the query array();

Thanks a lot again. Hope to get your reply soon.

Shahid


Shahid, I am obliged that this thread has been beneficial, sorry for delayed reply I took some vacation time and spent last week at Knowledge 11.

To do a more complex query not of the type x = y you can do encoded queries.



//use the getRecords function via encoded query

$s = new ServiceNowSoapClient(<credentials>);

//build encoded query
$eQ = array("__encoded_query"=>"closed_atBETWEENjavascript%3Ags.dateGenerate('".$resolveDateStart."')%40javascript%3Ags.dateGenerate('".$resolveDateEnd."') )";

var_dump( $s->getRecords( $eQ ) );



Something along those lines should work just fine and the javascript calls embedded within will be evaluated on the Service now server side!

Let me know if that helps or if you have any other questions.


Hi do you have any solution to get more than 250 records per SOAP request.

Thanks