Questions and discussion about developing processes and programming in PHP, JavaScript, web services & REST API.
Forum rules: Please search to see if a question has already asked before creating a new topic. Please don't post the same question in multiple forums.
#825348
Dear Amos,
I imported ExtraRest plugin to PM. I want to get user information. So, I created a process and wrote a trigger like this:
Code: Select all
$userId = '00000000000000000000000000000001';
$url = "/api/1.0/workflow/extrarest/user?usr_uid=$userId";
$oRet = pmRestRequest("GET", $url, null, $oToken->access_token);
print "\n\n".json_encode($oRet->response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)."\n\n";

//display user profile photo, if set:
if ($oRet->status == 200 and isset($oRet->response['usr_photo_url'])) {
   print '<img src="'.$oRet->response['usr_photo_url'].'">';
}
When I run the process, I see the following error:
Whoops, looks like something went wrong.
By the way I enabled debug mode, and I did not see errors.
I would be very thankful, if you could help me to find my fault
Kind Regards
#825378
Thanks for your kind reply,
I want to Update a user's account information (available in version 1.13 and later.)
In my sample process, I wrote the following trigger:
Code: Select all
$pmServer = "http://localhost:300";                                                                  
function pmRestRequest($method, $endpoint, $aVars = null, $accessToken = null) {
   global $pmServer;

   if (empty($accessToken) and isset($_COOKIE['access_token']))
      $accessToken = $_COOKIE['access_token'];

   if (empty($accessToken)) { //if the access token has expired
      //To check if the PM login session has expired: !isset($_COOKIE['PHPSESSID'])
      header("Location: loginForm.php"); //change to match your login method
      die();
   }

   //add beginning / to endpoint if it doesn't exist:
   if (!empty($endpoint) and $endpoint[0] != "/")
      $endpoint = "/" . $endpoint;

   $ch = curl_init($pmServer . $endpoint);
   curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer " . $accessToken));
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   $method = strtoupper($method);

   switch ($method) {
      case "GET":
         break;
      case "DELETE":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
         break;
      case "PUT":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
      case "POST":
         curl_setopt($ch, CURLOPT_POST, 1);
         curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($aVars));
         break;
      default:
         throw new Exception("Error: Invalid HTTP method '$method' $endpoint");
         return null;
   }

   $oRet = new StdClass;
   $oRet->response = json_decode(curl_exec($ch));
   $oRet->status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);

   if ($oRet->status == 401) { //if session has expired or bad login:
      header("Location: loginForm.php"); //change to match your login method
      die();
   }
   elseif ($oRet->status != 200 and $oRet->status != 201) { //if error
      if ($oRet->response and isset($oRet->response->error)) {
         print "Error in $pmServer:\nCode: {$oRet->response->error->code}\n" .
               "Message: {$oRet->response->error->message}\n";
      }
      else {
         print "Error: HTTP status code: $oRet->status\n";
      }
   }

   return $oRet;
}

$aUserProps = [
  
  'usr_username'                    => 'critiano',
  'usr_firstname'                   => 'Cristiano',
  'usr_lastname'                    => 'Ronaldo',
  'usr_email'                       => 'C.r@example.com',
  'usr_address'                     => "636 W. Almond Av.\nSan Pedro, CA 45837",
  'usr_zip_code'                    => '45135',
  'usr_country'                     => 'US',
  'usr_region'                      => 'CA', 
  'usr_location'                    => 'SPQ',
  'usr_phone'                       => '1-874-382-7633',
  'usr_position'                    => 'Chief accountant',
  'usr_replaced_by'                 => '2053768455c6cab4500e4b1062491650',
  'usr_due_date'                    => '2024-12-31',
  'usr_calendar'                    => '4244358425d0075ec7ede17084040535', 
  'usr_status'                      => 'VACATION',
  'usr_role'                        => 'PROCESSMAKER_MANAGER',
  'usr_time_zone'                   => 'America/New_York', 
  'usr_cost_by_hour'                => 15.50,
  'usr_unit_cost'                   => 'dollars',
  'usr_new_pass'                    => 'sample1234',
  'usr_cnf_pass'                    => 'sample1234',
  'usr_logged_next_time'            => 1,
  'usr_default_lang'                => 'en',
  'pref_default_lang'               => 'en',
  'pref_default_menuselected'       => 'PM_CASES',
  'pref_default_cases_menuselected' => 'CASES_SENT' 
   ];

$url = '/api/1.0/workflow/extrarest/user/update';
$oRet = pmRestRequest("PUT", $url, $aUserProps, $oToken->access_token, 'json');
print "\n\n".json_encode($oRet->response, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)."\n\n";

It sounds every thing is OK, however I do not know what is my wrong?
Would you please glimpse at my code?
Thanks in advance
#825381
I didn't realize that you were doing this inside a trigger.
Inside triggers you can't define global variables inside a function definition.
This doesn't work inside a trigger:
Code: Select all
function X() {
   global Y;
}
Here are functions that you need to use inside a trigger:
Code: Select all
/*Function to login to ProcessMaker using oAuth2.
Parameters:
 $clientId      The REST client ID (obtained when registrering the REST application).
 $clientSecret  The REST client secret code (obtained when registrering the REST application).
 $username      The ProcessMaker user's username.
 $password      The ProcessMaker user's password.
 $server        The protocol and domain or IP number (and port number if necessary). 
                If left empty or not included, then the current protocol and domain or 
                IP number will be used by default.
                Ex: "https://example.com:8080"
 $workspace     The ProcessMaker workspace. If empty or not included, then "workflow" by default.*/
function pmRestLogin($clientId, $clientSecret, $username, $password, $server='', $workspace='workflow') {
   $loginUrl = completeUrl("$server/$workspace/oauth2/token");
   $postParams = array(
      'grant_type'    => 'password',
      'scope'         => '*',       //set to 'view_process' if not changing the process
      'client_id'     => $clientId,
      'client_secret' => $clientSecret,
      'username'      => $username,
      'password'      => $password
   );
 
   $ch = curl_init($loginUrl);
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_POST, 1);
   curl_setopt($ch, CURLOPT_POSTFIELDS, $postParams);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
   $oToken = json_decode(curl_exec($ch));
   $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   if ($httpStatus != 200) {
      print "Error in HTTP status code: $httpStatus";
   }
   elseif (isset($oToken->error)) {
      print "Error logging into $pmServer:\n" .
         "Error:       {$oToken->error}\n" .
         "Description: {$oToken->error_description}\n";
   }
   else {
      //At this point $oToken->access_token can be used to call REST endpoints.
 
      //If planning to use the access_token later, either save the access_token
      //and refresh_token as cookies or save them to a file in a secure location.
 
      //If saving them as cookies:
      //setcookie("access_token",  $oToken->access_token,  time() + 86400);
      //setcookie("refresh_token", $oToken->refresh_token); //refresh token doesn't expire
      //setcookie("client_id",     $clientId);
      //setcookie("client_secret", $clientSecret);
 
      //If saving to a file:
      //file_put_contents("/secure/location/oauthAccess.json", json_encode($tokenData));
   }
 
   return $oToken;
}

 
/*Function to obtain a new access token, using a refresh token. If the parameters are not specified
then get them from the cookie if they exist. The new access token is set as a cookie available at $_COOKIE["access_token"]
Parameters:
 $server:       The protocol and domain or IP number (and port number if necessary). If not included, 
                then the current protocol and domain or IP number will be used by default.
                Ex: "https://example.com:8080"
 $workspace:    The ProcessMaker workspace. If not included, then "workflow" by default.
 $clientId:     The cliend ID.
 $clientSecret: The client secret code.
 $refreshToken: The refreshToken from a previous call to /oauth2/token endpoint.
Return value:
 Object returned by /oauth2/token endpoint, which either contains access token or error message.*/
function pmRestRefresh($server='', $workspace='workflow', $clientId=null, $clientSecret=null, $refreshToken=null) {
   $endpoint = completeUrl("$server/$workspace/oauth2/token");
   
   $clientId     = ($clientId     === null and isset($_COOKIE['client_id']))     ? $_COOKIE['client_id']     : $clientId;
   $clientSecret = ($clientSecret === null and isset($_COOKIE['client_secret'])) ? $_COOKIE['client_secret'] : $clientSecret;
   $refreshToken = ($refreshToken === null and isset($_COOKIE['refresh_token'])) ? $_COOKIE['refresh_token'] : $refreshToken;
 
   $aVars = array(
      'grant_type'    => 'refresh_token',
      'client_id'     => $clientId,
      'client_secret' => $clientSecret,
      'refresh_token' => $refreshToken
   );
 
   $ch = curl_init($endpoint);
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_POST, 1);
   curl_setopt($ch, CURLOPT_POSTFIELDS, $aVars);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
   $oToken = json_decode(curl_exec($ch));
   $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   if ($httpStatus != 200) {
      print "Error in HTTP status code: $httpStatus\n";
   }
   elseif (isset($oToken->error)) {
      print "Error logging into $pmServer:\n" .
         "Error:       {$oToken->error}\n" .
         "Description: {$oToken->description}\n";
   }
   else {
      //Save access token as a cookie that expires in 86400 seconds:
      setcookie("access_token",  $oToken->access_token, time() + 86400);
 
      //If saving to a file:
      //file_put_contents("/secure/location/oauthAccess.json", json_encode($oToken));
   }
   return $oToken;
}

/* Function to make sure that the REST endpoint is a complete URL by adding
the current protocol (http or https) and current server domain 
(or localhost if executing from command line) to the endpoint. */  
function completeUrl($endpoint) {
   $endpoint = trim($endpoint);
   
   if (preg_match('/^https?:\/\//', $endpoint) == 0) {       
       //add beginning / to endpoint if it doesn't exist:
       if (!empty($endpoint) and $endpoint[0] != "/") {
          $endpoint = "/" . $endpoint;
       }
       
       $host = empty($_SERVER['HTTP_HOST']) ? 'localhost' : $_SERVER['HTTP_HOST'];
       $protocol = "http";
        
       if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ||
          (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) 
       {
          $protocol = "https";
       }
       
       $endpoint = $protocol . "://" . $host . $endpoint;
   }
   return $endpoint;
}

/*Function to call a ProcessMaker REST endpoint and return the HTTP status code and
response if any.
Parameters:
 $method       HTTP method: "GET", "POST", "PUT" or "DELETE"
 $endpoint     The REST endpoint's URL. If "http(s)://{domain-or-ip}" is not included, then 
               the current server's address and port number will automatically be used.
               Ex: "/api/1.0/workflow/cases"
               Ex: "https://example.com:8080/api/1.0/workflow/cases"
 $aVars        Optional. Associative array containing the variables to use in the request
               if "POST" or "PUT" method.
 $accessToken  Optional. The access token, which comes from oauth2/token. If not defined
               then uses the access token in $_COOKIE['access_token']
 $postType     Optional. How the POST and PUT variables should be sent: 
               "query_string":  Default. The variables are passed through http_build_query(),
               "json":          The variables are converted into a JSON string,
               "existing_json": The variables are already in a JSON sting, 
               "automatic":     The variables are automatically converted into a simple query string, 
                                which means that variables cannot be arrays or objects.
                                Use this option if sending files. 
Return Value:
 object {
    response: Response from REST endpoint, decoded with json_decode().
    status:   HTTP status code: 200 (OK), 201 (Created), 400 (Bad Request), 404 (Not found), etc.
 }                                                                                              */
function pmRestRequest($method, $endpoint, $aVars = null, $accessToken = null, $postType='query_string') {
 
   if (empty($accessToken) and isset($_COOKIE['access_token']))
      $accessToken = $_COOKIE['access_token'];
 
   if (empty($accessToken)) { 
      throw new Exception("Access token is empty");
   }
   
   $endpoint = completeUrl($endpoint);
   $ch = curl_init($endpoint);
   curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer " . $accessToken));
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   $method = strtoupper($method);
 
   switch ($method) {
      case "GET":
         break;
         
      case "DELETE":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
         break;
         
      case "PUT":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
      case "POST":
         curl_setopt($ch, CURLOPT_POST, 1);
         if ($postType == 'json') {
            $aVars = json_encode($aVars);
         }
         elseif ($postType == 'query_string') {
            $aVars = http_build_query($aVars);
         }
         
         if ($postType == 'json' or $postType == 'existing_json') {
             curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                    'Authorization: Bearer ' . $accessToken,                                                                         
                    'Content-Type: application/json',                                                                                
                    'Content-Length: ' . strlen($aVars)
                )                                                                       
             );
         }
         curl_setopt($ch, CURLOPT_POSTFIELDS, $aVars);
         break;
         
      default:
         throw new Exception("Error: Invalid HTTP method '$method' $endpoint");
   }
 
   $oRet = new StdClass;
   $oRet->response = json_decode(curl_exec($ch));
   $oRet->status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   if ($oRet->status != 200 and $oRet->status != 201) { //if error
      if ($oRet->response and isset($oRet->response->error)) {
         throw new Exception("Error code: " . $oRet->response->error->code ."; ".
               "message: " . $oRet->response->error->message);
      }
      else {
         throw new Exception("Error: HTTP status code: " . $oRet->status);
      }
   }
 
   return $oRet;
}
Then, you can do a login and call the REST endpoint like this:
Code: Select all
$clientId = 'RVAFXUYBRBJXWVTBKPDJQHNYDACKQQFH';
$clientSecret = '46476331459d411f0ee63a6042490905';
$username = 'johndoe';
$password = 'p4sSw0rD';
$pmServer = 'http://localhost:8080';
$pmWorkspace = 'workflow';
$oToken = pmRestLogin($clientId, $clientSecret, $username, $password, $pmServer, $pmWorkspace);

$aUserProps = [
  'usr_username'                    => 'critiano',
  'usr_firstname'                   => 'Cristiano',
  'usr_lastname'                    => 'Ronaldo',
  'usr_email'                       => 'C.r@example.com',
  'usr_address'                     => "636 W. Almond Av.\nSan Pedro, CA 45837",
  'usr_zip_code'                    => '45135',
  'usr_country'                     => 'US',
  'usr_region'                      => 'CA', 
  'usr_location'                    => 'SPQ',
  'usr_phone'                       => '1-874-382-7633',
  'usr_position'                    => 'Chief accountant',
  'usr_replaced_by'                 => '2053768455c6cab4500e4b1062491650',
  'usr_due_date'                    => '2024-12-31',
  'usr_calendar'                    => '4244358425d0075ec7ede17084040535', 
  'usr_status'                      => 'VACATION',
  'usr_role'                        => 'PROCESSMAKER_MANAGER',
  'usr_time_zone'                   => 'America/New_York', 
  'usr_cost_by_hour'                => 15.50,
  'usr_unit_cost'                   => 'dollars',
  'usr_new_pass'                    => 'sample1234',
  'usr_cnf_pass'                    => 'sample1234',
  'usr_logged_next_time'            => 1,
  'usr_default_lang'                => 'en',
  'pref_default_lang'               => 'en',
  'pref_default_menuselected'       => 'PM_CASES',
  'pref_default_cases_menuselected' => 'CASES_SENT' 
];

$url = "$pmServer/api/1.0/$pmWorkspace/extrarest/user/update';
$oRet = pmRestRequest("PUT", $url, $aUserProps, $oToken->access_token, 'json');

if ($oRet->status != 200) {
   throw new Exception($oRet->response);
}

By the way, you probably should reread the REST documentation at https://wiki.processmaker.com/3.1/developer_info to make sure that you understand it.
Want to create your own meme coin?

In the world of cryptocurrencies, a unique and exc[…]

The market for cryptocurrencies is demonstrating a[…]

What's SAP FICO?

Embarking on a dissertation can be one of the most[…]

Hello. For rental housing, there are software solu[…]