GroupDocs Cloud SDK for PHP multiple questions

Hello I’m using the cloud api and php sdk and I’ve been working from these examples: http://groupdocs-php-samples.herokuapp.com/.

You guys have been aweseome about answering my questions so far but I have a couple more questions I was hoping you could help me with so I can finish up this implementation.

  1. I’ve successfully implemented the compress file into zip archive functionality on my local site but what if I want to zip a folder of files? The compress function takes the simple file id, not a guid and I can’t seem to find any examples or api functions that will allow the zipping of a folder of files.

  2. The convert file function from the async api takes an argument called $new_type. What are the possible types here? The documentation in the code is not too good. I need to know what types of strings this will take. If I want to convert a doc to a pdf do I just use ‘pdf’ as the $new_type. I’d prefer a list of possible arguments here.

  3. I have successsfully implemented the basic esignature but I am having trouble with the callback. My callback function is getting jobStatus always coming back as JobProgress… not JobCompleted as it needs to be from the example. What could be the problem? My callback function backend code is very similar to this sample http://groupdocs-php-samples.herokuapp.com/docs/sample40_callback.html .

  4. My last question is about esignature form fields (where the user actually puts their signature). My question is specifically about this function from signature api:

AddSignatureEnvelopeField($userId, $envelopeGuid, $documentGuid, $recipientGuid, $fieldGuid, $body=null)

In your example here: http://groupdocs-php-samples.herokuapp.com/docs/sample21.html, the $fildGuid is plugged in manually as a string like so:

$addEnvelopField = $signature->AddSignatureEnvelopeField($clientID, $envelop->result->envelope->id, $getDocuments->result->documents[0]->documentId, $recipientId, "0545e589fb3e27c9bb7a1f59d0e3fcb9", $signFieldEnvelopSettings)

What should I be using here in place of this string? It’s kind of odd that the example has a string hardcoded rather than getting the fileGuid from somewhere and passing it to this function as a var.

  1. When I use the add user as collaborator to annotation out of the AntApi I get this error code: The user has no right to manage this document. What does this mean?

Hello,

Thank you for your interest in GroupDocs. We will answer on your questions in order that you ask them.

  1. To package folder or files you should use “CreatePackage” method from Storage API. For how to use it please check this code:
$pathArray = array("documents");
$zipFolder = $storageApi->CreatePackage($clientId, "test2", true, $pathArray);

Whre:

“test2” - name of the package which will be created,

$pathArray – list of files or folders which will be packaged

In response you will get such object:

object(CreatePackageResponse)[10]
public 'result' =>
object(CreatePackageResult)[11]
public 'url' => string 'https://api.groupdocs.com/v2.0/shared/packages/ec925bdeab0ec67e813ca1785c0117a1/test2' (length=85)
public 'status' => string 'Ok' (length=2)
public 'error_message' => string '' (length=0)
public 'composedOn' => string '1402992719789' (length=13)

Please use “url” parameter from this object to get package.

  1. To get possible target file types (new type) for the conversion there is a method that returns the possible conversion targets based on the input file. For example input type jpg cannot have target file xsl, so it is depended. You may use getJobDocuments https://stage-api-groupdocs.dynabic.com/v2.0/spec/#!/async/GetJobDocuments_GET

The result is array from JobInputDocument, each jobDocumentInput contains OutputFormats, where the possible conversions types are defined

  1. When your document will be signed, our server will notify you with Job status “JobCompleted” via callback

  2. In the method “AddSignatureEnvelopeField” hard coded GUID is not file GUID, it’s a GUID of the field which will be added to the document. You can get all available GUID for fields by using this method Swagger API Explorer

  3. Could you please describe in details how you add collaborator that we can understand your use case. It will very helpful if you will share code example which adds collaborator that we can check it and explain how to do it properly. We have live sample for this functionality, please check our live demo sample here - http://groupdocs-php-samples.herokuapp.com/sample38

Please feel free to contact us if you have more questions, we will be glad to help you.

Thanks for the helping with this Pavel. I have a couple more questions here. I’m going in the same question order as before.

  1. Thanks for pointing me towards the createPackage method. Does the $pathArray arg take simple file id or file guid? Must I list out files by their string name in this array? It would be preferable to select files by a unique identifier of some kind.
  2. Great answer! I will do this.
  3. Yes, I have implemented the esignature and am successfully signing documents but my callback never receieves a jobCompleted response its always JobProgress even after I have successfully signed one… Not sure what’s wrong there.
  4. Great Answer!
  5. Here is code example:
$basePath = ‘https://api.groupdocs.cloud/v2.0’;
$mgmtApi->setBasePath($basePath);
$antApi->setBasePath($basePath);
$storageApi->setBasePath($basePath);
//add a new user first
$user = new UserInfo();
$role = new RoleInfo();
$role->id = “3”;
$role->name = “User”;
$roles = array($role);
$user->nickname = $crmeryUser->first_name;
$user->firstname = $crmeryUser->first_name;
$user->lastname = $crmeryUser->last_name;
$user->roles = $roles;
$user->primary_email = $thisuser->email;
$newUser = $mgmtApi->UpdateAccountUser($this->clientId, $thisuser->email, $user);
if ($newUser->status == “Ok”) {
//Make a request to Annotation API using clientId and fileId
try {
$response = $antApi->SetAnnotationCollaborators($this->clientId, $document->groupdocs_file_id, “v2.0”, $collaborations);
if ($response->status == “Ok”) {
//Check the result of the request
if (isset($response->result)) {
//If request was successfull - set annotations variable for template
return $response->result;
}
} else {
throw new Exception($response->error_message);
}
} catch (Exception $e) {
$error = 'groupdocs.php model line 1083 ERROR: ’ . $e->getMessage() . “\n”;
$this->logErrorDB($error);
}
} else {
$error = 'groupdocs.php model line 1104 ERROR: newUser->status does not equal ok. problem adding user. '.$newUser->error_message."\n";
$this->logErrorDB($error);
}

Hello,

Thank you for coming back with additional questions. We will reply to questions which need additional explanation (answers that were already answered will be skipped).

  1. In the “CreatePackage” method you should use array of file paths. For example if we need to create package with two files we will create such array: array(“someFolder/firstFile.pdf”, “someFolder/secondFile.doc”) or if you need to package all folder you can just put this folder path to the array, for example array(”someFolderPath”).

  2. Could you please share job ID that we can check this job. Thanks.

  3. First of all please check that value of your $collaborations variable is the array of emails. Also we checked your account and found out that you have two users, please try to delete them and then try again.

Please feel free to contact us if you have more
questions.

Pavel,

  1. I think the information you provided is sufficient for me to continue work.

  2. Please check status of envelope 60497 to see if it’s jobCompleted?

  3. Could you please explain why I would need to delete these users? When the app is finished and fully running in beta, I don’t see why I would need to delete users ever? Yes, the collaboration variable is the array of emails. (In this case it’s just one email). I don’t think I’m having any trouble creating users its just that I can’t add them to annotate a document.

This snippet of code from my prior example:

$response = $antApi->SetAnnotationCollaborators($this->clientId, $document->groupdocs_file_id, “v2.0”, $collaborations);
if ($response->status == “Ok”) {
//Check the result of the request
if (isset($response->result)) {
//If request was successfull - set annotations variable for template
return $response->result;
}
} else {
throw new Exception($response->error_message);
}

$response->status is not equal to “Ok” and it is throwing the above exception. The var $response->error_message is equal to The user has no right to manage this document.

I have one additional question about the conversion, when I am calling getJobDocuments what is the jobId or guid refer to? How would I call this function can you provide an example of how I would go about this is a case where I have 1 file, say file.pdf and I want to find out the possible conversion types?

Also wanted to note that I’m getting emails from group docs letting me know that envelopes have been successfully signed. But my callback is still having jobStatus == jobProgress and it never records a jobCompleted…

This is the code that handles the esignature callback

//include and create the needed classes
if ( (class_exists(‘GroupDocsRequestSigner’)) &&
(class_exists(‘APIClient’)) &&
(class_exists(‘StorageApi’)) &&
(class_exists(‘SignatureApi’)) ) { //instances already exist
//Create Signer, ApiClient and Storage Api objects
$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
$storageApi = new StorageApi($apiClient);
$signatureApi = new SignatureApi($apiClient);
} else { //load the needed library files
include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/APIClient.php’);
include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/StorageApi.php’);
include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/GroupDocsRequestSigner.php’);
include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/FileStream.php’);
include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/SignatureApi.php’);

$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
$storageApi = new StorageApi($apiClient);
$signatureApi = new SignatureApi($apiClient);
}
//handle callback
$callBack_data = json_decode($json, true);
//Get job id from array
$formId = $callBack_data[“SourceId”];
$jobStatus = $callBack_data[“EventType”];
$serializedData = json_decode($callBack_data[‘SerializedData’], true);
$participant = $serializedData[‘ParticipantGuid’];
//check to see if we’re done signing
if ($jobStatus == “JobCompleted”) {
//lets get the signed document
$getDocInfo = $signatureApi->GetSignatureFormParticipant($formId, $participant);
if ($getDocInfo->status == “Ok”) { //this is the signed document
$guid = $getDocInfo->result->participant->documentGuid; //signed docs guid
//lets log the contents of the getDocInfo call
$error = json_encode($getDocInfo);
$this->logErrorDB($error);
//return $getDocInfo; //return the information about signed document
} else {
$error = 'groupdocs.php model line 405 getDocInfo->status does not equal Ok, it equals '.$getDocInfo->status;
$this->logErrorDB($error);
}
} else {
$error = 'groupdocs.php model line 402 jobStatus var does not equal JobCompleted, it equals '.$jobStatus;
$this->logErrorDB($error);
}

Just one more additional question about the CreatePackage method, the url property from the object that is returned after creating a package. How do I use the url property? when I go to the page in my browser it downloads the zip file, but what about if I want to download the file to a specific folder on my server? how would I go about doing this?

Hello,

Thank you for your additional request and additional data. As before, we will reply in the order in which the questions were asked (answers that were already answered will be skipped).

  1. We checked provided by you envelop ID and found out that this envelop doesn’t have any callbacks. Please check that you set correct URL for callback when you use this method: https://api.groupdocs.com/v2.0/spec/#!/signature/SignatureEnvelopeSend_PUT .

  2. We checked your account and found out that you are trying to add collaborator by using user credentials which is not an owner of the document, you should use Client ID and Private Key of your main GroupDocs account. Please double check that you use correct credentials.

  3. To get possible conversion types for files you should use this code:

$signer = new GroupDocsRequestSigner($apiKey);
//Create apiClient object
$apiClient = new APIClient($signer);
//Create Storage Api object
$storageApi = new StorageApi($apiClient);
$asyncApi = new AsyncApi($apiClient);
$files = $storageApi->ListEntities($clientId, '', 0);
if ($files->status == "Ok") {
//Selecting file names
foreach ($files->result->files as $item) {
if ($item->name == $name) {
$guid = $item->guid;
}
}
}
//Create job info object
$jobInfo = new JobInfo();
$jobInfo->actions = "convert";
$jobInfo->status = -1;
$jobInfo->email_results = true;
$jobInfo->name = "test" . rand(0, 500);
//Create new job
$createJob = $asyncApi->CreateJob($clientId, $jobInfo);
if ($createJob->status == "Ok") {
//Add uploaded documents to job
$addJobDocument = $asyncApi->AddJobDocument($clientId, $createJob->result->job_id, $guid, false);
$getJobDocument = $asyncApi->GetJobDocuments($clientId, $createJob->result->job_id);
$targetTypes = "";
$targetTypes = $getJobDocument->result->inputs[0]->SupportedOutputFileTypes;
//Change job status
$jobInfo->status = 0;
$jobInfo->out_formats = array($targetTypes);
//Update job with new status
$updateJob = $asyncApi->UpdateJob($clientId, $createJob->result->job_id, $jobInfo);
}

We tested this and found out a small bug which already fixed and this fix will be released in nearest time.

  1. To download package to your local server you should use standard PHP approach. In code it will looks like that:

file_put_contents("packageName.zip", fopen("url", 'r'));

Where url – URL which you get from “CreatePackage” method.

Please note: in that case .zip will be downloaded to the root of your project. If you need some other location you should set relative path instead “packageName.zip” (for example: “/downloads/packageName.zip”). Also file can be downloaded only to the folder which is in the project.

Thanks can you help me with another thing please?

I’m trying to convert 1 html file into a PDF file. I’m doing the code as you’ve explained but it doesn’t seem my pdf is getting created on the groupdocs server. Can you please check on this below job for me. The below object is what was output from $asyncApi->GetJobDocuments($this->clientId, $createJob->result->job_id);

{

“result”:{

“job_status”:“Postponed”,

“inputs”:[

{“status”:“Processed”,

“proc_date”:“1403288504277”,

“output_formats”:“Pdf”,

“outputs”:null,

“job_errors”:[],

“actions”:“Convert, Combine”,

“supported_output_file_types”:null,

“name”:“ljkhlkjhlkjh-20140620-132142.html”,

“version”:1,

“size”:“377”,

“type”:“Html”,

“type_str”:“Html”,

“file_type_str”:“Html”,

“document_path”:“457\ljkhlkjhlkjh-20140620-132142.html”,

“access”:“Private”,

“url”:“hxxxs://api.groupdocs.com/v2.0/shared/files/94d35a14d87217128c28da74854729980498fb8b7c3a553a41e2371e7053399d”,

“file_type”:“Html”,

“id”:601174,

“guid”:“94d35a14d87217128c28da74854729980498fb8b7c3a553a41e2371e7053399d”}],

“outputs”:[

{

“error”:"",

“name”:"",

“version”:0,

“size”:“0”,

“type”:“Cells”,

“type_str”:“Cells”,

“file_type_str”:“Pdf”,

“document_path”:"",

“access”:“Private”,

“url”:"",

“file_type”:“Pdf”,

“id”:0,

“guid”:""

}

]

}

]

},

“status”:“Ok”,

“error_message”:"",

“composedOn”:“1403288513730”

}

What do I need to do to be able to generate the PDF from the html? Can you tell if anything is wrong in the above object?

The GetJobDocuments method from async api takes a job id or guid. If I want to use GetJobDocuments in the way you described before (so I can see the OutputFormats for doc conversion) how would I call this function. At this point in my code I don’t want to create a job, I just want to know based on the file the user selected what conversions are possible, that way I can list them out in a for users to select what conversion they would like to perform.

I’m also still getting the response when adding a collaborator to annotate a document: ERROR: The user has no right to manage this document.

I’ve checked my clientId and privateKey and they are the ones that are in the account section when logged into groupdocs under Api. The top of the screen says “My API Key”. These are the only keys that are listed in my account. Please advise.

Hello,

Thank you for your request. We checked the object that you provided and found out that you should place definition of “out_formats” just after job action, should be:

$jobInfo = new JobInfo();
$jobInfo->actions = "convert, combine";
$jobInfo->out_formats = array("pdf");

As for making list of available file types for convert - You can’t just get them without creation of “Job” and adding files to it, there is no such API. We may implement such API for PHP SDK, but it will take some time of course.

To resolve the issue with collaboration could you please share with us client id and file guid that you use for this functional that we can check them. Also please try to log-off from GroupDocs (or try in another browser) and then try again to add collaborator and annotate document.

Also you can share with us example of your project and we will check and fix it for you.

Please feel free to contact us if you will have more questions.

With relation to converting HTML file to PDF, the “out_formats” has always been just after job action. Like so:

//Create job info object
$jobInfo = new JobInfo();
$jobInfo->actions = "convert, combine";
$jobInfo->out_formats = array("pdf");
$jobInfo->status = -1;
$jobInfo->email_results = true;
$jobInfo->name = $formName;

The object I posted before is what is returned to me by your api when I try to do the HTML to PDF conversion. It says job postponed. How do I get this job to run and complete? I am really confused by all of this “job” business. How do I fire/run/complete job? I go through all of this booboo creating jobs and at the end of it, I don’t have a converted file… I am using this code from an example on your groupdocs php heroku sample site. Please see the php here:

function generateGroupDocsPDF($html,$formName) {

$user =& JFactory::getUser();

if ( (class_exists('GroupDocsRequestSigner')) &&

(class_exists('APIClient')) &&

(class_exists('StorageApi')) &&

(class_exists('AsyncApi')) ) { //instances already exist

//Create Signer, ApiClient and Storage Api objects
$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
$storageApi = new StorageApi($apiClient);
$asyncApi = new AsyncApi($apiClient);

} else { //load the needed library files

include_once(JPATH_COMPONENT . '/libraries/groupdocs/APIClient.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/StorageApi.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/GroupDocsRequestSigner.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/FileStream.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/AsyncApi.php');

//Create Signer, ApiClient and Storage Api objects
$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
$storageApi = new StorageApi($apiClient);
$asyncApi = new AsyncApi($apiClient);

}

$basePath = 'https://api.groupdocs.com/v2.0';
$storageApi->setBasePath($basePath);
$asyncApi->setBasePath($basePath);
$formName = preg_replace('/\s+/', '', $formName); //replace all white space

//first lets save the html to a .html file locally
$fileName = $formName.'-'.strftime('%G%m%d-%H%M%S').'.html';
$filePath = JPATH_COMPONENT.'/documents/'.$user->id.'/'.$fileName;
file_put_contents($filePath,$html);
chmod($filePath, 0755);

//now lets upload the html file to groupdocs
$fs = FileStream::fromFile( $filePath );
$gdPath = $user->id.'/'.$fileName;
//$gdPath = $document->name;
//upload the html file to groupdocs
//make the api call

try {

//$uploadResult = $storageApi->UploadWeb($this->clientID, $url);
$uploadResult = $storageApi->Upload($this->clientId, $gdPath, 'uploaded', "", $fs);

if ($uploadResult->status == "Ok") { //successful upload

$guid = $uploadResult->result->guid;
//$simpleId = $uploadResult->result->id;

try {

//Create job info object
$jobInfo = new JobInfo();
$jobInfo->actions = "convert, combine";
$jobInfo->out_formats = array("pdf");
$jobInfo->status = -1;
$jobInfo->email_results = true;
$jobInfo->name = $formName;
$createJob = $asyncApi->CreateJob($this->clientId, $jobInfo);

if ($createJob->status == "Ok") {

try {

$addJobDocument = $asyncApi->AddJobDocument($this->clientId, $createJob->result->job_id, $guid, false);

if ($addJobDocument->status != "Ok") {

throw new Exception($addJobDocument->error_message);

}

} catch (Exception $e) {

$error = 'ERROR: ' . $e->getMessage() . "\n";
$this->logErrorDB($error);

}

try {

$jobInfo->status = 0;
$updateJob = $asyncApi->UpdateJob($this->clientId, $createJob->result->job_id, $jobInfo);

if ($updateJob->status == "Ok") {

try {

sleep(8);
$getJobDocument = $asyncApi->GetJobDocuments($this->clientId, $createJob->result->job_id);

if ($getJobDocument->status == "Ok") {

$this->logErrorDB(json_encode($getJobDocument)); //debug

/**
* SUCCESSFUL conversion to PDF
* download the new file to uncategorized and store in documents area and database
*/

$result = $formName.'.pdf';//remove all whitespace from string

if ($this->checkForExistingDocument($result)) {

//the file exists
/*$error = 'this file has already been compressed';
$response = new stdClass;
$response->filename = "error";
$response->message = $error;*/
/**

*
* RENAME THE FILE WITH A (1) OR SOMETHING
* //TEST THIS IMPLEMENTATION
**/

$fileNameParts = explode('.',$result);
$newFileString = $fileNameParts[count($fileNameParts) - 2] . '(1)';
$newFileName = $newFileString .'.'. $fileNameParts[count($fileNameParts) - 1];

//find the right file name
$number = 1;

for ($count=0;$count<1;$count++) {

if ($this->checkForExistingDocument($newFileName)) { //that name already exists

$count--; //start over
$number++; //increment the number, last number already existed
$newFileString = $fileNameParts[count($fileNameParts) - 2] . '('.$number.')';
$newFileName = $newFileString .'.'. $fileNameParts[count($fileNameParts) - 1];

} else {

$newFileString = $fileNameParts[count($fileNameParts) - 2] . '('.$number.')';
$newFileName = $newFileString .'.'. $fileNameParts[count($fileNameParts) - 1];

}

}

$result = $newFileName;

} else {

//it doesn't exist

}

//download pdf file and rename to hash only if conversion succesfully created pdf

if ($getJobDocument->result->outputs[0]->guid !="") {

//download file from groupdocs to com_crmery's document folder for that user
$downloadPath = JPATH_COMPONENT.DS.'documents'.DS.$user->id;
$this->downloadFromGroupDocs($downloadPath,$getJobDocument->result->outputs[0]->guid,$result);
$data = array(
'name' => $result,
'groupdocs_simple_file_id' => $getJobDocument->result->outputs[0]->id,
'groupdocs_file_id' => $getJobDocument->result->outputs[0]->guid
);

$file = $this->storeFileDbInfo($data);
//rename the file from human friendly filename to hash file name
rename(JPATH_COMPONENT.DS.'documents'.DS.$user->id.DS.$result,JPATH_COMPONENT.DS.'documents'.DS.$user->id.DS.$file['filename']);
return 'https://apps.groupdocs.com/document-viewer/embed/' . $getJobDocument->result->outputs[0]->guid;

} else { //log an error

$error = 'groupdocs.php model line 1177 ERROR: pdf file was not created. No Guid for the new file in the outputs var from getJobDocument.';
$this->logErrorDB($error);

}

} else {

throw new Exception($getJobDocument->error_message);

}

} catch (Exception $e) {

$error = 'ERROR: ' . $e->getMessage() . "\n";
$this->logErrorDB($error);

}

} else {

throw new Exception($updateJob->error_message);

}

} catch (Exception $e) {

$error = 'ERROR: ' . $e->getMessage() . "\n";
$this->logErrorDB($error);

}

} else {

throw new Exception($createJob->error_message);

}

} catch (Exception $e) {

$error = 'ERROR: ' . $e->getMessage() . "\n";
$this->logErrorDB($error);

}

} else {

throw new Exception($uploadResult->error_message);

}

} catch (Exception $e) {

$error = "groupdocs.php line 1073 uploadResult->status does not equal Ok ERROR: ".$e->getMessage();
$this->logErrorDB(); //log for debugging ajax requests

}

}

For general document conversion I want to be able to show a html for users to decide what conversion they would like to perform. (Like on your site.) I need a list of available conversions so I can list the choices in a select! How are users supposed to decide what kind of doc conversion they are supposed to perform? If I have to create a job every time I want to show a choice for conversion there are going to be alot of uncompleted jobs hanging out in the account in limbo which will never be completed. Not to mention all of the unnecessary steps. Please just send me a list of the conversion types. Surely you know what they are as there is an api function that returns me this information. Just give me the api function source with it’s switch statement or whatever so I can see what choices there are… I can even write my own server side function for this and not use yours. I know this depends on the input file… send me all of the information with choices for each input file please. I am fine creating a job and such after the user chooses to perform a conversion, but I can’t be just creating jobs everytime a user opens the conversion modal (where the conversion html with available conversions will be. (I was going to attach a screenshot but your site says I don’t have permission to send files?.. I am a paying user.

I’m running the annotation api functions on my site, not on your groupdocs site… why would logging off of groupdocs.com do anything for me? Or trying another browser? The part that is causing trouble is at the server level and has nothing to do with the browser.

clientId: 2635e55e54866ba8
fileGuid: 13f6ba1e210414db4027190d532322d6eab075b98788fa7bf0b1a8a9425018e6

Please see the annotation code below:

function addUserAsGroupDocsCollaborator($crmeryUser,$document) {
$thisuser = JFactory::getUser($crmeryUser->uid);
$collaborations = array($thisuser->email);

if ( (class_exists('GroupDocsRequestSigner')) &&

(class_exists('APIClient')) &&

(class_exists('StorageApi')) &&

(class_exists('AntApi')) &&

(class_exists('MgmtApi')) ) { //instances already exist

//Create Signer, ApiClient and Storage Api objects
$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
$storageApi = new StorageApi($apiClient);
$antApi = new AntApi($apiClient);
$mgmtApi = new MgmtApi($apiClient);

} else { //load the needed library files

include_once(JPATH_COMPONENT . '/libraries/groupdocs/APIClient.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/StorageApi.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/GroupDocsRequestSigner.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/FileStream.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/AntApi.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/MgmtApi.php');
$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
//Create Storage Api object
$storageApi = new StorageApi($apiClient);
$antApi = new AntApi($apiClient);
$mgmtApi = new MgmtApi($apiClient);

}

$basePath = 'https://api.groupdocs.com/v2.0';
$mgmtApi->setBasePath($basePath);
$antApi->setBasePath($basePath);
$storageApi->setBasePath($basePath);

//add a new user first
$user = new UserInfo();
$role = new RoleInfo();
$role->id = "3";
$role->name = "User";
$roles = array($role);
$user->nickname = $crmeryUser->first_name;
$user->firstname = $crmeryUser->first_name;
$user->lastname = $crmeryUser->last_name;
$user->roles = $roles;
$user->primary_email = $thisuser->email;
$newUser = $mgmtApi->UpdateAccountUser($this->clientId, $thisuser->email, $user);

if ($newUser->status == "Ok") {

//Make a request to Annotation API using clientId and fileId

try {

$response = $antApi->SetAnnotationCollaborators($this->clientId, $document->groupdocs_file_id, "v2.0", $collaborations);

if ($response->status == "Ok") {

//Check the result of the request

if (isset($response->result)) {

//If request was successfull - set annotations variable for template

return $response->result;

}

} else {

throw new Exception($response->error_message);

}

} catch (Exception $e) {

$error = 'groupdocs.php model line 1083 ERROR: ' . $e->getMessage() . "\n";
$this->logErrorDB($error);

}

} else {

$error = 'groupdocs.php model line 1104 ERROR: newUser->status does not equal ok. problem adding user. '.$newUser->error_message."\n";
$this->logErrorDB($error);

}

}

Here is the error I receive from your api:

groupdocs.php model line 1083 ERROR: The user has no right to manage this document.

Please help me with these, I want very much to finish this up and to stop bothering you with questions.

Hello,

Thank you for sharing your code and requested IDs. We checked your code and found out that you made almost all right. There is only one mistake, as we can see from your code you add only one document to the job. In such case job action can’t be “convert, combine” it should be “convert”. If you need to set action “convert, combine” you should add at least 2 documents. So please try to add second file (or more files) or to change action to “convert”.

As for issue with collaborators – we checked this functional with your client ID and file GUID and found out that there was the hung session in your account. We fixed this issue and tried again with your credentials – all works fine for as.

Also we created a table with all possible conversion types for you here - Supported Document Formats | GroupDocs.Conversion Cloud | Documentation

Please try again and notify us if all works well for you.

  1. Thanks for providing me with that nice table, that helped immensely, convert functions are all working now.

  2. Thanks, collaborators are working now.

I have one last thing and I should be able to finish up. My esignature callback still doesn’t seem to be getting a JobCompleted status in the callback. I am recording an error in my program: jobStatus var does not equal JobCompleted, it equals JobProgress. I’m not getting a JobCompleted status for my signatures.

Can you check the following envelope:

94b0aaa43aad8657fac621b0f2db896a

Why am I not getting a JobCompleted response back? If I was getting one, my program would store it and the response object in a database table where I can easily see responses and errors that happen at various parts of the program.

Here is the callback function:

//handle the esignature callback
function handleGroupDocsEsignatureCallBack($json) {

//include and create the needed classes

if ( (class_exists('GroupDocsRequestSigner')) && (class_exists('APIClient')) &&(class_exists('StorageApi')) && 
(class_exists('SignatureApi')) ) { //instances already exist

//Create Signer, ApiClient and Storage Api objects
$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
$storageApi = new StorageApi($apiClient);
$signatureApi = new SignatureApi($apiClient);

} else { //load the needed library files

include_once(JPATH_COMPONENT . '/libraries/groupdocs/APIClient.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/StorageApi.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/GroupDocsRequestSigner.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/FileStream.php');
include_once(JPATH_COMPONENT . '/libraries/groupdocs/SignatureApi.php');
$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
$storageApi = new StorageApi($apiClient);
$signatureApi = new SignatureApi($apiClient);

}

//handle callback

$callBack_data = json_decode($json, true);
//Get job id from array
$formId = $callBack_data["SourceId"];
$jobStatus = $callBack_data["EventType"];
$serializedData = json_decode($callBack_data['SerializedData'], true);
$participant = $serializedData['ParticipantGuid'];

//check to see if we're done signing
if ($jobStatus == "JobCompleted") {

//lets get the signed document
$getDocInfo = $signatureApi->GetSignatureFormParticipant($formId, $participant);

if ($getDocInfo->status == "Ok") { //this is the signed document

$guid = $getDocInfo->result->participant->documentGuid; //signed docs guid

//
//lets log the contents of the getDocInfo call
$error = json_encode($getDocInfo);
$this->logErrorDB($error);
//return $getDocInfo; //return the information about signed document

} else {

$error = 'groupdocs.php model line 405 getDocInfo->status does not equal Ok, it equals '.$getDocInfo->status;
$this->logErrorDB($error);

}

} else {

$error = 'groupdocs.php model line 402 jobStatus var does not equal JobCompleted, it equals '.$jobStatus;
$this->logErrorDB($error);

}

}

You can see that my program is firing the final else condition logging an error in the database as 'groupdocs.php model line 402 jobStatus var does not equal JobCompleted, it equals '.$jobStatus;

It never records the $getDocInfo object in the database table.

Hello,

It’s great news that the issue with collaborators is resolved. As for JobStatus in the callback – we checked your envelop and found out that all fine with it. Could you please try again to create envelop, send it and sign it.

If you will have more questions please feel free to contact us. Notify

Thanks for the help. I have everything working now except for one small issue with the callback.

I have recorded callbacks with JobCompleted status but I’m having trouble due to inconsistent contents of the callback vars.

For debugging purposes I am recording just about everything about the esignature process.

Let me show you what I mean:

2014-06-25 11:42:00 - generation of envelope

esignature envelop var: {“result”:{“envelope”:{“id”:“6d7dc868377cc860f712fe49efa773e4”,“name”:“20140625-114153-newestform(1).pdf”,“creationDateTime”:“2014-06-25T16:41:56.4970000Z”,“updatedDateTime”:“2014-06-25T16:41:56.6322900ZZ”,“ownerGuid”:“2635e55e54866ba8”,“status”:-1,“statusDateTime”:“1970-01-01T00:00:00.0000000ZZ”,“reminderTime”:1,“stepExpireTime”:3,“envelopeExpireTime”:6,“ownerShouldSign”:false,“orderedSignature”:false,“emailSubject”:"",“emailBody”:"",“documentsCount”:1,“documentsPages”:1,“recipients”:[],“waterMarkText”:"",“waterMarkImage”:"",“attachSignedDocument”:false,“includeViewLink”:true,“canBeCommented”:true,“inPersonSign”:false,“ownerName”:“Emmanuel Sullivan”}},“status”:“Ok”,“error_message”:"",“composedOn”:“1403714516492”}

2014-06-25 11:42:00 - add the signers to envelope

here are the signers: [{“firstname”:“Mike”,“lastname”:“Hill”,“email”:“mwhill86@gmail.com”}]

2014-06-25 11:42:06 - first callback

{“SourceId”:“6d7dc868377cc860f712fe49efa773e4”,“EventType”:“JobProgress”,“SerializedData”:"{“StatusId”:1,“OwnerGuid”:“2635e55e54866ba8”}",“TimeStamp”:1403714527.1514683}

2014-06-25 11:42:22 - second callback

{“SourceId”:“6d7dc868377cc860f712fe49efa773e4”,“EventType”:“JobProgress”,“SerializedData”:"{“StatusId”:99,“OwnerGuid”:“2635e55e54866ba8”}",“TimeStamp”:1403714543.9673512}

2014-06-25 11:42:36 - third callback

{“SourceId”:“6d7dc868377cc860f712fe49efa773e4”,“EventType”:“JobProgress”,“SerializedData”:"{“StatusId”:5,“OwnerGuid”:“2635e55e54866ba8”}",“TimeStamp”:1403714557.5538769}

2014-06-25 11:42:36 - fourth callback

{“SourceId”:“6d7dc868377cc860f712fe49efa773e4”,“EventType”:“JobCompleted”,“SerializedData”:“null”,“TimeStamp”:1403714557.5738642}

Above you can see the contents of each callback and on the fourth callback there is an EventType of JobCompleted. Yes! this is what we needed. Except you can see the SerializedData on this callback is null. Also the SerializedData that are in the 1st through 3rd callbacks is an object but it doesn’t contain the var $participant = $serializedData[‘ParticipantGuid’];

Without this ParticipantGuid var I can’t get the signed documents. Am I missing something here?

Once more here is my code:

//handle the esignature callback
function handleGroupDocsEsignatureCallBack($json) {

//include and create the needed classes

if ( (class_exists(‘GroupDocsRequestSigner’)) && (class_exists(‘APIClient’)) && 
(class_exists(‘StorageApi’)) && (class_exists(‘SignatureApi’)) ) 
{ //instances already exist

//Create Signer, ApiClient and Storage Api objects
$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
$storageApi = new StorageApi($apiClient);
$signatureApi = new SignatureApi($apiClient);

} else { //load the needed library files

include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/APIClient.php’);
include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/StorageApi.php’);
include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/GroupDocsRequestSigner.php’);
include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/FileStream.php’);
include_once(JPATH_COMPONENT . ‘/libraries/groupdocs/SignatureApi.php’);
$signer = new GroupDocsRequestSigner($this->privateKey);
$apiClient = new APIClient($signer);
$storageApi = new StorageApi($apiClient);
$signatureApi = new SignatureApi($apiClient);

}

//handle callback

$callBack_data = json_decode($json, true);
$this->logErrorDB($json);

//Get job id from array

$formId = $callBack_data[“SourceId”];
$jobStatus = trim($callBack_data[“EventType”]);
$serializedData = json_decode($callBack_data[‘SerializedData’], true);
//$this->logErrorDB($callBack_data[‘SerializedData’]);
$participant = $serializedData[‘ParticipantGuid’];
$this->logErrorDB($jobStatus);

//check to see if we’re done signing

if ($jobStatus == “JobCompleted” || $jobStatus == ‘JobCompleted’) {

//lets get the signed document
$this->logErrorDB(‘we are finally inside the dreaded jobcompleted conditional. jeez!’);
//$getDocInfo = $signatureApi->GetSignatureFormParticipant($formId, $participant);
//$this->logErrorDB(json_encode($getDocInfo));

try {

$getDocInfo = $signatureApi->GetSignatureFormParticipant($formId, $participant);

if ($getDocInfo->status == “Ok”) { //this is the signed document

$guid = $getDocInfo->result->participant->documentGuid; //signed docs guid
//
//lets log the contents of the getDocInfo call
$this->logErrorDB(‘We can get the signed document, everything is good’);
//return $getDocInfo; //return the information about signed document

} else {

throw new Exception($getDocInfo->error_message);

}

} catch (Exception $e) {

$error = "groupdocs.php line 749 something wrong with getDocInfo call: ".$getDocInfo->error_message;
$this->logErrorDB($error);

}

} else {

$error = 'groupdocs.php model line 402 jobStatus var does not equal JobCompleted, it equals '.$jobStatus;
$this->logErrorDB($error);

}

}

Hello,

We glad to hear that now all works fine and you get job status completed. In the callback object in case that job is completed “SerializedData” null is ok. In such case our server return to you envelop guid in the callback, this guid is a “SourceId”. You can get signed document by using this envelop guid. To do that you can use this code:

//Get raw data
$json = file_get_contents("php://input");
//path to settings file - temporary save userId and apiKey like to property file
//Decode json with raw data to array
$callBack_data = json_decode($json, true);
//Get job id from array
$envelopeId = $callBack_data["SourceId"];
$jobStatus = $callBack_data["EventType"];

if ($jobStatus == "JobCompleted") {

//Create signer object
$signer = new GroupDocsRequestSigner(trim($privateKey));
//Create apiClient object
$apiClient = new APIClient($signer);
//Create AsyncApi object
$signatureApi = new SignatureApi($apiClient);
//Create Storage Api object
$storageApi = new StorageApi($apiClient);
$getDocInfo = $signatureApi->GetSignatureEnvelopeDocuments($clientId, $envelopeId);

if ($getDocInfo->status == "Ok") {

$name = $getDocInfo->result->documents[0]->name;
//Local path to the downloads folder
$downloadFolder = dirname(__FILE__) . 'path for downolads';
//Check is folder exist

if (!file_exists($downloadFolder)) {

//If folder don't exist create it
mkdir($downloadFolder);

}

//Obtaining file stream of downloading file and definition of folder where to download file
$outFileStream = FileStream::fromHttp($downloadFolder, $name);
$document = $signatureApi->GetSignedEnvelopeDocuments($clientId, $envelopeId, $outFileStream);

}

}

If you will have more questions please feel free to contact us.

Thanks for this pavel. You have been a great help.

I have one more question, on your esignature demo that is on the groupdocs site, users can drag the signature fields around on the page and put them where they would like. Is this possible with php sdk and api that I am using?

Right now I specify where the field goes (what page and x and y coords):

$signFieldEnvelopSettings = new SignatureEnvelopeFieldSettingsInfo();
$signFieldEnvelopSettings->locationX = “0.15”;
$signFieldEnvelopSettings->locationY = “0.73”;
$signFieldEnvelopSettings->locationWidth = “150”;
$signFieldEnvelopSettings->locationHeight = “50”;
$signFieldEnvelopSettings->name = “test” . rand(0, 500);
$signFieldEnvelopSettings->forceNewField = true;
$signFieldEnvelopSettings->page = “1”;

Is there some other way to do this so that the user can put the signature field where they want (drag it around to the part of the page where the signature should be)?

Hello,

We are glad to hear that all issues are resolved. We assume that you ask for the functional that available in the GroupDocs site when you create envelope. When you create envelope from GroupDocs.Signature for Cloud APP and add signature field to the document the cloud app will create field by the same code which you call from the API (it will call same API functional). Since that the only way to add this to your Web page is to create your own UI which will allow this functional. For this you will be needed:

1 Show to user all available fields – you can get them by using this functions:

https://stage-api-groupdocs.dynabic.com/v2.0/spec/#!/signature/GetSignatureEnvelopeFields_GET

https://stage-api-groupdocs.dynabic.com/v2.0/spec/#!/signature/GetFieldsList_GET

2 Dynamically get coordinates and size for the field when user add it and use them in the

$signFieldEnvelopSettings->locationX = "0.15";
$signFieldEnvelopSettings->locationY = "0.73";
$signFieldEnvelopSettings->locationWidth = "150";
$signFieldEnvelopSettings->locationHeight = "50";

3 Create field via Api when user finish with adding – for example click a button “Finish”

If you will have more questions please feel free to contact us.