SOAP
SOAP is probably the most used Web Services protocol. It provides a way of exchanging structured information of application functionality. A SOAP interface can be defined by its Web Service Description Language (WSDL) file, which simply provides the definitions of all available methods to the client. One of the biggest attractions to using SOAP as a Web Service over lighter weight services, such as REST, is that it makes interacting with remote Web Services as seamless as making local function calls. It can do this because SOAP support in various languages mimic object method calls, allowing use of built-in data types with them automatically making the needed conversions between the data provided by a method to those used in the class itself
We’ll focus on the newer version of SOAP interface. SugarCRM will continue to support backwards compatibility of the previous SOAP interface, which has been in use for many versions now. We recommend you upgrade to the newer libraries because they are much more efficient than the older libraries (less calls needed to accomplish the same end results in the newer library versus the old), as well as make it easier to write custom SOAP methods.
Let’s look at a few common actions and how to do them with the SOAP interface.
You’ll use the nusoap PHP SOAP library for all of the following examples, but they should translate easily into the language/library of your choice.
Make a Connection
To begin, you need to connect to the service. You start this process by initializing the SOAP object with the URL of the SOAP instance, then using the login method to authenticate against the Sugar instance. Listing 4-11 provides the implementation.
Listing 4-11. Connecting to the Sugar Instance Using SOAP
// Create the SOAP client instance
$soapclient = new nusoapclient(‘http://sugar_root_url/service/v2/soap.php?wsdl’, true);
// Login to the server
$result = $soapclient->call(‘login’,array(‘user_auth’=>array(‘user_name’=>$user_name,
‘password’=>md5($user_password), ‘version’=>’.01′), ‘application_name’=>’SoapTest’));
$session = $result[‘id’];
// Get the user_id of the logged on user
$user_id = $soapclient->call(‘get_user_id’,array(‘session’=>$session));
You pass the credentials that you are using to login to the instance using the ‘user_auth’ parameter of the login method. The array key ‘user_name’ specifies the user name and the key ‘password’ specifies the password, which you need to pass md5 encoded for added security. Returned from this method call, among other things, is the session_id, which is returned as in the ‘id’ key element of the array.
This key is important, since you’ll need to pass it along as the first argument to all further soap function calls.
One performance issue you have seen is when dealing with the WSDL file.
Loading it on every SOAP client call can degrade performance considerably. I have seen up to 40 percent performance improvement by simply caching the WSDL file locally, instead of loading it from the remote source every time. NuSOAP provide a class to do such a thing, called wsdlcache, which integrates nicely into the NuSOAP client (see Listing 4-12).
Listing 4-12. Caching the WSDL File with NuSOAP
$cache = new wsdlcache(“C:\temp”, $cachelifetimeinseconds);
$wsdl = $cache->get(“http://localhost/soap.php?wsdl”);
if (is_null($wsdl)) {
// Retrieve the WSDL file and store it in the cache
$wsdl = new wsdl(“http://localhost/soap.php?wsdl”);
$cache->put($wsdl);
} else {
$wsdl->debug_str = ”;
$wsdl->debug(‘Retrieved from cache’);
} // else
// instantiate the soap client using the cached wsdl file
$soapclient = new nusoapclient($wsdl, true);
You can see in Listing 4-12 how to establish a WSDL cache location and check to see if the WDSL file you need is in the cache. If it isn’t, you can use the put() method of the wsdlcache object to store the retrieved WSDL file. Finally, you specify the wsdlcache object instance instead of a URL as the first parameter to the nusoapclient constructor to use the cached WSDL file, rather than retrieving it from the remote source every time. Note that using WSDL files are not required by this SOAP service.
It’s merely provided as a convenience. You could always choose not to pull the WSDL file when you initiate the SOAP connection (in NuSOAP, you would pass false to the second argument of the nusoapclient constructor).
Get Lists and Counts of Records
Now that you can establish a connection to the SOAP server, let’s try to actually query the data there. A good place to start is by trying to get a count of records available for a module. In Listing 4-13, you’ll do this for the Accounts module, returning the number of non-deleted records back to you.
Listing 4-13. Get a Count of Records in a Module
// Create the SOAP client instance
$soapclient = new nusoapclient(‘http://sugar_root_url/service/v2/soap.php?wsdl’, true);
// Login to the server
$result = $soapclient->call(‘login’,array(‘user_auth’=>array(‘user_name’=>
$user_name,’password’=>md5($user_password), ‘version’=>’.01′),
‘application_name’=>’SoapTest’));
$session = $result[‘id’];
// Get the count of records
$result = $soapclient->call(‘get_entries_count’,array(‘session’=>$session,
‘module_name’ => ‘Accounts’, ‘query’ => ”, ‘deleted’ => 0));
$count = $result[‘result_count’];
You initialize your SOAP instance and login, and then make the get_entries_count SOAP call. You’ll pass the session id as a parameter, as well as the name of the module which you are querying. The query parameter to the call allows you to add extra conditions to the records being counted. For example, you could set it to ‘array(‘industry = ‘Banking’)’ to return only accounts in the Banking industry.
The deleted parameter at the end specifies that you only want non-deleted records counted.
Extending this example, let’s now actually get the records for a module. The SOAP call you’ll use here is get_entry_list, which returns an array of fields for the given parameter specified. Listing 4-14 shows an example of this in action for retrieving all Contacts in the Sugar instance.
Listing 4-14. Get All Contacts in a Module
// Create the SOAP client instance
$soapclient = new nusoapclient(‘http://sugar_root_url/service/v2/soap.php?wsdl’, true);
// Login to the server
$result = $soapclient->call(‘login’,array(‘user_auth’=>array(‘user_name’=>$user_name,
‘password’=>md5($user_password), ‘version’=>’.01′), ‘application_name’=>’SoapTest’));
$session = $result[‘id’];
// Get the list of records
$result = $soapclient->call(‘get_entry_list’,array(‘session’=>$session,’module_name’=>
‘Contacts’,’query’=>”, ‘order_by’=>”,’offset’=>0,’select_fields’=>array(),
‘link_name_to_fields_array’ => ”, ‘max_results’=>10,’deleted’=>-1));
$records_returned = $result[‘result_count’];
$next_offset = $result[‘next_offset’];
$field_list = $result[‘entry_list’];
The actual records retrieved will be in the $field list array. The $records_returned and $next_offset integer values are handy if you want to page the returned results—in case you expect the result set to be large and want to handle it chunk by chunk (just like the SugarCRM ListViews only deal with 20 records at a time). To handle thempaging, you can specify the ‘offset’ parameter to the get_entry_list method to the result given by $next_offset, limiting the page set size by the ‘max_results’ parameter. You’ll know when you’ve reached the end when the method call returns no records or the $records_returned is less than the value used for ‘max_results’.
Add a New Record
Adding a record is a fairly straightforward exercise. The set_entry method call is used here, where you will specify an array of name/value pairs that each record should be set to. Listing 4-15 has the code for this example.
Listing 4-15. Add a New Record with set_entry
// Create the SOAP client instance
$soapclient = new nusoapclient(‘http://sugar_root_url/service/v2/soap.php?wsdl’, true);
// Login to the server
$result = $soapclient->call(‘login’,array(‘user_auth’=>array(‘user_name’=>$user_name,
‘password’=>md5($user_password), ‘version’=>’.01′), ‘application_name’=>’SoapTest’));
$session = $result[‘id’];
// Add the new record
$result = $soapclient->call(‘set_entry’,array(‘session’=>$session,’module_name’=>
‘Contacts’, ‘name_value_list’=>array(array(‘name’=>’last_name’ , ‘value’=>”Mertic”),
array(‘name’=>’first_name’ , ‘value’=>’John’))));
$id = $result[‘id’];
The ‘name_value_list’ parameter you use is an array with each field specified.
The ‘name’ key in the subarray is the name of the field you’ll be setting, while the ‘value’ field is the value. The resulting record id is returned back in the ‘id’ key of the $result array, which you quickly grab and store in a local variable.
You use the same method for also updating records. In this case, you just need to specify what the id of the record to update is. Assuming the previous record was successfully created in Listing 4-15, you’ll extend that example to update the newly created Contact record with a title in Listing 4-16.
Listing 4-16. Add a New Contact Record and Then Update It
// Create the SOAP client instance
$soapclient = new nusoapclient(‘http://sugar_root_url/service/v2/soap.php?wsdl’, true);
// Login to the server
$result = $soapclient->call(‘login’,array(‘user_auth’=>array(‘user_name’=>$user_name,
‘password’=>md5($user_password), ‘version’=>’.01′), ‘application_name’=>’SoapTest’));
$session = $result[‘id’];
// Add the new record
$result = $soapclient->call(‘set_entry’,array(‘session’=>$session, ‘module_name’=>
‘Contacts’, ‘name_value_list’=>array(array(‘name’=>’last_name’ ,
‘value’=>”Mertic”), array(‘name’=>’first_name’ , ‘value’=>’John’))));
$id = $result[‘id’];
// Now change a field in the newly created record
$result = $soapclient->call(‘set_entry’,array(‘session’=>$session,’module_name’=>
‘Contacts’, ‘name_value_list’=>array(array(‘name’=>’id’ , ‘value’=>$id),
array(‘name’=>’title’ , ‘value’=>’Author’))));
$id = $result[‘id’];
Let’s say you have a bunch of records to update or create in one shot for a module. Instead of having to do several set_entry calls in a row, you can save yourself the extra network time and use the set_entries method (notice that it’s plural) to do several changes in one shot. The biggest difference is that now the ‘name_value_list’ parameter becomes ‘name_value_lists’ (again, plural). Listing 4-17 has all the code
details.
Listing 4-17. Creating Multiple Records with set_entries
// Create the SOAP client instance
$soapclient = new nusoapclient(‘http://sugar_root_url/service/v2/soap.php?wsdl’, true);
// Login to the server
$result = $soapclient->call(‘login’,array(‘user_auth’=>array(‘user_name’=>$user_name,
‘password’=>md5($user_password), ‘version’=>’.01′), ‘application_name’=>’SoapTest’));
$session = $result[‘id’];
// Specify the list of records to add
$name_value_lists[] = array(array(‘name’=>’last_name’ , ‘value’=>”Mertic”),
array(‘name’=>’first_name’ , ‘value’=>’John’));
$name_value_lists[] = array(array(‘name’=>’last_name’ , ‘value’=>”Mertic”),
array(‘name’=>’first_name’ , ‘value’=>’Dominic’));
$name_value_lists[] = array(array(‘name’=>’last_name’ , ‘value’=>”Mertic”),
array(‘name’=>’first_name’ , ‘value’=>’Mallory’));
// Now add all the new records
$result = $soapclient->call(‘set_entries’,array(‘session’=>$session,’module_name’=>
‘Contacts’, ‘name_value_lists’=>$name_value_lists));
$ids = $result[‘ids’];
You specify the records to create or update the same way as before, but this time wrap them in one more array, using that array as the value for the ‘name_value_lists’ parameter in the SOAP method call. The returned result is similar as well, this time returning an ‘ids’ key with the array list of ids created or updated.
Saving and Retrieving Attachments
Don’t let simple record creation stop you in your SOAP integration. You can also upload and retrieve attachments as well, such as those used in the Notes module. You do this as a secondary call instead of using set_entry, like you would for normal record data. Here you use the set_note_attachment method to upload the actual file to the Sugar instance record. Listing 4-18 shows you how to do this for the Notes module.
Listing 4-18. Add a New Notes Record with an Attachment
// Create the SOAP client instance
$soapclient = new nusoapclient(‘http://sugar_root_url/service/v2/soap.php?wsdl’, true);
// Login to the server
$result = $soapclient->call(‘login’,array(‘user_auth’=>array(‘user_name’=>$user_name,
‘password’=>md5($user_password), ‘version’=>’.01′), ‘application_name’=>’SoapTest’));
$session = $result[‘id’];
// Add the new note record
$result = $soapclient->call(‘set_entry’,array(‘session’=>$session,’module_name’=>
‘Notes’, ‘name_value_list’=>array(array(‘name’=>’name’ , ‘value’=>”My new note”),
array(‘name’=>’description’ , ‘value’=>’This is a note with a file attached to it’))));
$id = $result[‘id’];
// Now attach the file to the newly created note
$file = base64_encode(file_get_contents(‘attach.txt’));
$result = $soapclient->call(‘set_note_attachment’,array(‘session’=>$session,
‘note’=>array(‘id’=>$id, ‘filename’=>’attach.txt’,’file’=>$file) ));
$id = $result[‘id’];
You create the file attachment from the local file named ‘attach.txt’. You grab the contents of it and base64 encode it for transport in the SOAP method call, passing it under the parameter ‘file’. You also need to specify the actual name of the file as it should be stored on the server in the ‘filename’ attribute.
What comes in must come out as well, so the get_note_attachment method call provides this functionality. Here you’ll assume the existence of record in the Notes module already, and you’ll assume you already know the id of that record (which is provided in the $id variable). Listing 4-19 shows the details on the more interesting parts of the file retrieval process.
Listing 4-19. Grab a Given Notes Record Attachment
// Create the SOAP client instance
$soapclient = new nusoapclient(‘http://sugar_root_url/service/v2/soap.php?wsdl’, true);
// Login to the server
$result = $soapclient->call(‘login’,array(‘user_auth’=>array(‘user_name’=>$user_name,
‘password’=>md5($user_password), ‘version’=>’.01′), ‘application_name’=>’SoapTest’));
$session = $result[‘id’];
// Grab the given record’s attachment
$result = $soapclient->call(‘get_note_attachment’,array(‘session’=>$session,
‘id’=>$note_id ));
$file_contents = base64_decode($result[‘note_attachment’][‘file’]);
$filename = $result[‘note_attachment’][‘filename’];
// Now store the contents in a local file
file_put_contents($filename,$file_contents);
The get_note_attachment method is very simple, returning back an array with all the file details. Everything you are looking for is under the ‘note_attachment’ key, with two subarray keys, ‘file’ and ‘filename’, giving you the actual file content (this is base64 encoded, so you need to decode for your use), as well as the name of the file as it existing in the Sugar instance. You take these two elements and use them with the file_put_contents() method for saving the file on your local filesystem while also using the same name as it was on the server.
Relate Records
One nice part about SugarCRM is the ability to have records from different modules relate to one another. In the same way, the SOAP interface provides the same sort of ability through the set_relationship method call. Listing 4-20 shows you how to do this by relating a Contact to an Account record.
Listing 4-20. Relating a Contact with an Account Using SOAP
// Create the SOAP client instance
$soapclient = new nusoapclient(‘http://sugar_root_url/service/v2/soap.php?wsdl’, true);
// Login to the server
$result = $soapclient->call(‘login’,array(‘user_auth’=>array(‘user_name’=>$user_name,
$session = $result[‘id’];
// Add the new Contact record
$result = $soapclient->call(‘set_entry’,array(‘session’=>$session,’module_name’=>
‘Contacts’, ‘name_value_list’=>array(array(‘name’=>’last_name’ , ‘value’=>”Mertic”),
array(‘name’=>’first_name’ , ‘value’=>’John’))));
$contact_id = $result[‘id’];
// Add the new Account record
$result = $soapclient->call(‘set_entry’,array(‘session’=>$session,
‘module_name’=>’Accounts’, ‘name_value_list’=>array(array(‘name’=>’name’ , ‘value’=>
“John’s House of Cards”))));
$account_id = $result[‘id’];
// Now relate the contact to the account
$result = $soapclient->call(‘set_relationship’,array(‘session’=>$session,
‘module_name’ => ‘Accounts’, ‘module_id’ => $account_id, ‘link_field_name’ =>
‘contacts’, ‘related_ids’ => array($contact_id)));
After you create the two new records, you relate them using the set_relationship method. You first specify the parent module name and id in the ‘module_name’ and ‘module_id’ parameters. You then indicate which link field you are using to relate with the target module. In the case of the Accounts module, the link field name for the Contact module relationship is ‘contacts’. Finally, you specify an array list of contact ids that should be marked as being related to the given account_id in the related_ids parameter.