REST API PHP Library

Forum for users and developers of Bullhorn's new REST API service.

Moderators: StaffingSupport, s.emmons, BullhornSupport

mavieo
User
Posts: 11
Joined: Mon Apr 10, 2017 2:01 pm

REST API PHP Library

Postby mavieo » Thu Apr 13, 2017 12:01 pm

Through days of trial and error, working with support, debugging, etc., I finally have a pretty simple PHP library for authenticating and handling candidate entities (including raw resume upload) through the REST API.

Hoping this will assist someone new to the API with a practical implementation.

Library

Code: Select all

<?php

class BullhornAPI {
   const API_USERNAME = '[created via support ticket]';
   const API_PASSWORD = '[set in admin]';
   const CLIENT_ID = '[created via support ticket]';
   const CLIENT_SECRET = '[created via support ticket]';
   const ENDPOINT_AUTH_CODE = 'https://auth.bullhornstaffing.com/oauth/authorize?%s';
   const ENDPOINT_ACCESS_TOKEN = 'https://rest-west.bullhornstaffing.com/oauth/token?%s';
   const ENDPOINT_REST_TOKEN = 'https://rest.bullhornstaffing.com/rest-services/login?version=*&access_token=%s';
   const PUBLIC_ERROR = 'We\'re unable to process your application at this time. Contact a site administrator to learn more.';
   const RESUME_FILE_TYPE = 'Resume'; # Must exist in BH account
   const REWIND_CREATE_ON_RESUME_FAIL = TRUE;
   const SHOW_LOG = FALSE;

   private $access_token;
   private $auth_code;
   private $comm_response;
   private $comm_response_info;
   private $errors = array();
   private $is_dev = FALSE;
   private $refresh_token;
   private $rest_token;
   private $rest_endpoint_url;

   public function __construct() {
      if(function_exists('is_dev')) :
         $this->is_dev = (bool) is_dev();
      endif;
   }

   public function candidateAttachResume($candidate_id, $resume_path=NULL, $resume_filename=NULL) {
      if(TRUE !== $this->oAuth()) :
         return FALSE;
      endif;

      if(in_array(self::RESUME_FILE_TYPE, array(NULL, ''))) :
         $this->errorsSet('Empty resume file type.', __LINE__, __METHOD__);
         return FALSE;
      endif;

      if(NULL === $resume_path) :
         $this->errorsSet('Empty resume path.', __LINE__, __METHOD__);
         return FALSE;
      endif;

      if(!is_readable($resume_path)) :
         $this->errorsSet('Unable to locate resume.', __LINE__, __METHOD__);
         return FALSE;
      endif;

      if(function_exists('finfo_open')) :
         $finfo = finfo_open(FILEINFO_MIME_TYPE);
         $content_type = finfo_file($finfo, $resume_path);
         finfo_close($finfo);
      else :
         $content_type = '';
      endif;

      $comm_args = array(
         'externalID' => 'PORTFOLIO',
         'fileType' => self::RESUME_FILE_TYPE,
         'description' => 'Candidate resume',
         'type' => 'resume',
         'content_type' => $content_type,
         'file' => array(
            'filename' => empty($resume_filename) || !is_string($resume_filename) ? 'resume.txt' : trim($resume_filename),
            'name' => 'Resume',
            'path' => $resume_path,
         ),
      );

      if(FALSE === $this->comm(sprintf('file/Candidate/%d/raw', $candidate_id), 'FILE', $comm_args)) :
         return FALSE;
      endif;

      if(!isset($this->comm_response['fileId'])) :
         $this->errorsSet('fileId not present in response', __LINE__, __METHOD__);
         return FALSE;
      endif;

      return TRUE;
   }

   public function candidateCreate($args=array(), $resume_path=NULL, $resume_filename=NULL) {
      if(TRUE !== $this->oAuth()) :
         return FALSE;
      endif;

      if(FALSE === ($comm_args = self::candidatePrepData($args))) :
         return FALSE;
      endif;

      if(FALSE === $this->comm('entity/Candidate', 'PUT', $comm_args)) :
         return FALSE;
      endif;

      if(NULL !== $resume_path) :
         $candidate_id = $this->comm_response['changedEntityId'];

         if(FALSE === $this->candidateAttachResume($candidate_id, $resume_path, $resume_filename)) :
            if(TRUE === self::REWIND_CREATE_ON_RESUME_FAIL) :
               $this->candidateDelete($candidate_id);
            endif;

            return FALSE;
         endif;
      endif;

      return TRUE;
   }

   public function candidateDelete($candidate_ids=NULL) {
      if(TRUE !== $this->oAuth()) :
         return FALSE;
      endif;

      $candidate_ids = !is_array($candidate_ids) ? explode(',', $candidate_ids) : $candidate_ids;
      $candidate_ids = array_map('trim', $candidate_ids);
      $candidate_ids = array_filter($candidate_ids, 'strlen');
      $candidate_ids = array_unique($candidate_ids);

      foreach($candidate_ids as $candidate_id) :
         if(!is_numeric($candidate_id)) :
            ob_start(); var_dump($candidate_id);

            $this->errorsSet(array(
               'Delete aborted: Invalid candidate id',
               'Candidate id: '.ob_get_clean(),
            ), __METHOD__, __LINE__);

            continue;
         endif;

         $this->log('Deleting candidate '.$candidate_id);

         $comm_args = array(
            'isDeleted' => '1',
         );

         if(FALSE === $this->comm('entity/Candidate/'.$candidate_id, 'POST', $comm_args)) :
            $this->log('Failed to delete candidate '.$candidate_id);
         endif;
      endforeach;

      return 0 === sizeof($this->errors);
   }

   public function candidateFind($args=array(), $return_ids=FALSE) {
      if(TRUE !== $this->oAuth()) :
         return FALSE;

      endif;

      $args = array_merge(array(
         'first_name' => '',
         'last_name' => '',
         'email' => '',
         'is_deleted' => '0',
      ), $args);

      $select_args = array(
         'and' => $args,
      );

      if(NULL === ($query = $this->searchBuildQuery($select_args, array('id', 'first_name', 'last_name', 'email')))) :
         $this->errorsSet(array(
            'Failed to build search query',
         ), __LINE__, __METHOD__);

         return FALSE;
      endif;

      if(FALSE === $this->comm(sprintf('search/Candidate?%s', $query), 'GET')) :
         return FALSE;
      endif;

      if(!is_array($this->comm_response) || !isset($this->comm_response['total']) || 0 === $this->comm_response['total'] || !isset($this->comm_response['data'][0])) :
         return NULL;
      endif;

      $perfect_matches = array();
      foreach($this->comm_response['data'] as $match) :
         if(1 !== (int) $match['_score']) :
            continue;
         endif;

         $perfect_matches[] = $match;
      endforeach;

      if(empty($perfect_matches)) :
         return NULL;
      endif;

      if(FALSE === $return_ids) :
         return $perfect_matches;
      endif;

      $return = array();
      foreach($perfect_matches as $match) :
         $return[] = $match['id'];
      endforeach;

      return $return;
   }

   private static function candidatePrepData($data=array()) {
      if(!is_array($data) || empty($data)) :
         $this->errorsSet('Invalid candidate data', __LINE__, __METHOD__);
         return FALSE;
      endif;

      if(isset($data['gender'])) :
         $data['gender'] = substr($data['gender'], 0, 1);
      endif;

      if(isset($data['veteran'])) :
         $data['veteran'] = substr($data['veteran'], 0, 1);
      endif;

      if(isset($data['occupation']) && 50 < strlen($data['occupation'])) :
         $data['occupation'] = substr($data['occupation'], 0, 47).'...';
      endif;

      if(isset($data['referredBy']) && 50 < strlen($data['referredBy'])) :
         $data['referredBy'] = substr($data['referredBy'], 0, 47).'...';
      endif;

      foreach(array('dateAvailable') as $date_field) :
         if(isset($data[$date_field]) && !empty($data[$date_field])) :
            if(FALSE === ($date_field_ts = strtotime($data[$date_field]))) :
               unset($data[$date_field]);
            else :
               # Add 12 hours so BH admin doesn't use the incorrect day...
               # 01/01/2018 was being inserted as 12/31/2017
               $date_field_ts += 3600*12;
            
               # Convert it to milliseconds so BH API knows what to do with it
               # Convert it to an int so BH API doesn't complain about invalid scalar
               $date_field_ts = (int) $date_field_ts*1000;
            
               $data[$date_field] = $date_field_ts;
            endif;
         endif;
      endforeach;
      
      return $data;
   }

   public function candidateUpdate($candidate_id=NULL, $args=array(), $resume_path=NULL, $resume_filename=NULL) {
      if(TRUE !== $this->oAuth()) :
         return FALSE;
      endif;

      if(empty($candidate_id) || !is_numeric($candidate_id)) :
         ob_start(); var_dump($candidate_id);

         $this->errorsSet(array(
            'Delete aborted: Invalid candidate id',
            'Candidate id: '.ob_get_clean(),
         ), __METHOD__, __LINE__);
         
         return FALSE;
      endif;

      if(FALSE === ($comm_args = self::candidatePrepData($args))) :
         return FALSE;
      endif;

      if(FALSE === $this->comm('entity/Candidate/'.$candidate_id, 'POST', $comm_args)) :
         return FALSE;
      endif;

      if(NULL !== $resume_path) :
         if(FALSE === $this->candidateAttachResume($candidate_id, $resume_path, $resume_filename)) :
            return FALSE;
         endif;
      endif;

      return TRUE;
   }

   private function comm($endpoint_script=NULL, $endpoint_method=NULL, $endpoint_args=array(), $endpoint_url=NULL, $verify_response=TRUE) {
      $endpoint_args = !is_array($endpoint_args) ? array() : $endpoint_args;

      $this->comm_response = NULL;
      $this->comm_response_info = NULL;

      if(NULL === $endpoint_url) :
         $endpoint_url = $this->rest_endpoint_url.ltrim($endpoint_script, '/');
      endif;

      if(!empty($this->rest_token)) :
         $bh_token_param = '?BhRestToken='.urlencode($this->rest_token).'&';

         if(strstr($endpoint_url, '?')) :
            $endpoint_url = str_replace('?', $bh_token_param, $endpoint_url);
         else :
            $endpoint_url = $endpoint_url.$bh_token_param;
         endif;
      elseif(strstr($endpoint_url, '?')) :
         $endpoint_url = rtrim($endpoint_url, '&').'&';
      else :
         $endpoint_url = $endpoint_url.'?';
      endif;

      switch($endpoint_method) :
         case 'FILE' :
            if(!isset($endpoint_args['file'])) :
               $this->errorsSet('missing argument "file"', __LINE__, __METHOD__);
               return FALSE;
            endif;

            $file = $endpoint_args['file'];
            unset($endpoint_args['file']);

            if(FALSE === is_readable($file['path'])) :
               $this->errorsSet('Failed to locate path', __LINE__, __METHOD__);
               return FALSE;
            else :
               $file['contents'] = file_get_contents($file['path']);
            endif;

            $multipart_name = !isset($file['name']) || empty($file['name']) ? 'Unknown' : $file['name'];
            $multipart_filename = !isset($file['filename']) || empty($file['filename']) ? 'unknown' : $file['filename'];

            $multipart_new_line = "\r\n";
            $multipart_boundary = md5(time());
            $multipart_body  = '--'.$multipart_boundary.$multipart_new_line;
            $multipart_body .= 'Content-Disposition: form-data; name="'.$multipart_name.'"; filename="'.$multipart_filename.'"'.$multipart_new_line;
            $multipart_body .= 'Content-Length: '.strlen($file['contents']).$multipart_new_line;
            $multipart_body .= 'Content-Type: application/octet-stream'.$multipart_new_line;
            $multipart_body .= 'Content-Transfer-Encoding: binary'.$multipart_new_line.$multipart_new_line;
            $multipart_body .= $file['contents'].$multipart_new_line;
            $multipart_body .= '--'.$multipart_boundary.'--'.$multipart_new_line.$multipart_new_line;

            $endpoint_url_qs = empty($endpoint_args) ? '' : http_build_query($endpoint_args);

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $endpoint_url.$endpoint_url_qs);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::ENDPOINT_TIMEOUT);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); # Don't use CURLOPT_PUT (results in a "read timed out" error)
            curl_setopt($ch, CURLOPT_BINARYTRANSFER, TRUE);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $multipart_body);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array(
               'Content-Type: multipart/form-data; boundary='.$multipart_boundary,
            ));
         break;
         case 'GET' :
            $endpoint_url_qs = empty($endpoint_args) ? '' : http_build_query($endpoint_args);

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $endpoint_url.$endpoint_url_qs);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::ENDPOINT_TIMEOUT);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
         break;
         case 'POST' :
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $endpoint_url);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::ENDPOINT_TIMEOUT);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
            curl_setopt($ch, CURLOPT_POST, TRUE);

            if(!empty($endpoint_args)) :
               $endpoint_args_string = json_encode($endpoint_args);

               curl_setopt($ch, CURLOPT_POSTFIELDS, $endpoint_args_string);
               curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                  'Content-Type: application/json',
                  'Content-Length: '.strlen($endpoint_args_string),
               ));
            endif;
         break;
         case 'PUT' :
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $endpoint_url);
            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::ENDPOINT_TIMEOUT);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); # Don't use CURLOPT_PUT (results in a "read timed out")

            if(!empty($endpoint_args)) :
               $endpoint_args_string = json_encode($endpoint_args);

               curl_setopt($ch, CURLOPT_POSTFIELDS, $endpoint_args_string);
               curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                  'Content-Type: application/json',
                  'Content-Length: '.strlen($endpoint_args_string),
               ));
            endif;
         break;
         default :
            ob_start();
            var_dump($method);
   
            $this->errorsSet(array(
               'Comm error (method)',
               'Invalid endpoint method ('.ob_get_clean().')',
            ), __LINE__, __METHOD__);
   
            return FALSE;
         break;
      endswitch;

      $this->comm_response = curl_exec($ch);
      $this->comm_response_info = curl_getinfo($ch);
      curl_close($ch);

      if(FALSE === $this->comm_response) :
         $this->errorsSet(array(
            'Comm error (cURL)',
            'Endpoint: '.$endpoint_url,
            'REST method: '.$endpoint_method,
            'REST args: '.((empty($endpoint_args)) ? 'NULL' : json_encode($endpoint_args)),
            'Error: '.curl_error($ch),
         ), __LINE__, __METHOD__);

         return FALSE;
      endif;

      if(TRUE === $verify_response) :
         if(NULL === ($this->comm_response = json_decode($this->comm_response, TRUE))) :
            $this->errorsSet(array(
               'Comm error (Failed to decode response)',
               'Endpoint: '.$endpoint_url,
               'REST method: '.$endpoint_method,
               'REST args: '.((empty($endpoint_args)) ? 'NULL' : json_encode($endpoint_args)),
               'Response: '.$this->comm_response,
               'Response info: '.json_encode($this->comm_response_info),
            ), __LINE__, __METHOD__);

            return FALSE;
         endif;

         if(!is_array($this->comm_response)) :
            $this->errorsSet(array(
               'Comm error (Response is not an array)',
               'Endpoint: '.$endpoint_url,
               'REST method: '.$endpoint_method,
               'REST args: '.((empty($endpoint_args)) ? 'NULL' : json_encode($endpoint_args)),
               'Response: '.$this->comm_response,
               'Response info: '.json_encode($this->comm_response_info),
            ), __LINE__, __METHOD__);

            return FALSE;
         endif;
      endif;

      if(is_array($this->comm_response) && isset($this->comm_response['error']) || isset($this->comm_response['errorCode'])) :
         $this->errorsSet(array(
            'Comm error (Endpoint error)',
            'Endpoint: '.$endpoint_url,
            'REST method: '.$endpoint_method,
            'REST args: '.((empty($endpoint_args)) ? 'NULL' : json_encode($endpoint_args)),
            'Response: '.json_encode($this->comm_response),
            'Response info: '.json_encode($this->comm_response_info),
         ), __LINE__, __METHOD__);

         return FALSE;
      endif;

      return $this->comm_response;
   }

   public function errorsGetAll() {
      return $this->errors;
   }

   public function errorsGetLast() {
      return empty($this->errors) ? NULL : end($this->errors);
   }

   private function errorsSet($message=NULL, $line=NULL, $method=NULL) {
      if(TRUE !== $this->is_dev) :
         $message = self::PUBLIC_ERROR;
      endif;

      $message = !is_array($message) ? array($message) : $message;
      $prefix = '';
      $suffix = '';

      if(TRUE !== $this->is_dev) :
         $prefix = empty($line) ? '' : '[Err'.$line.']';
      else :
         array_unshift($message, 'Method: '.$method, 'Line: '.$line);
      endif;

      $message = implode('<br>', $message);
      $message = trim($prefix.' '.$message.' '.$suffix);

      $this->errors[] = array('method' => $method, 'line' => $line, 'message' => $message);
      return TRUE;
   }

   private function log($msg) {
      if(FALSE === $this->is_dev || FALSE === self::SHOW_LOG) :
         return;
      endif;

      echo $msg.'<br>';
   }

   private function oAuth() {
      if('' === self::CLIENT_ID || '' === self::CLIENT_SECRET || '' === self::API_USERNAME || '' === self::API_PASSWORD) :
         $this->errorsSet(array(
            'Empty client id, client secret, api username, or api password.',
            'Follow instructions located at: http://developer.bullhorn.com/articles/getting_started',
            'Hint: Request API access via support ticket',
         ), __LINE__, __METHOD__);

         return FALSE;
      endif;

      if(TRUE !== $this->oAuthSetRestToken()) :
         return FALSE;
      endif;

      if(TRUE !== $this->oAuthLogin()) :
         return FALSE;
      endif;

      return TRUE;
   }

   private function oAuthLogin() {
      if(FALSE === $this->comm(NULL, 'POST', $args, sprintf(self::ENDPOINT_REST_TOKEN, urlencode($this->access_token)))) :
         return FALSE;            
      endif;

      $this->rest_endpoint_url = $this->comm_response['restUrl'];
      $this->rest_token = $this->comm_response['BhRestToken'];

      return TRUE;
   }

   private function oAuthSetAuthCode($force=FALSE) {
      if(FALSE === $force && !empty($this->auth_code)) :
         return TRUE;
      endif;

      $comm_args = array(
         'client_id' => self::CLIENT_ID,
         'response_type' => 'code',
         'username' => self::API_USERNAME,
         'password' => self::API_PASSWORD,
         'action' => 'Login',
      );

      $comm_url = sprintf(self::ENDPOINT_AUTH_CODE, http_build_query($comm_args));

      if(FALSE === $this->comm(NULL, 'GET', NULL, $comm_url, FALSE)) :
         return FALSE;
      endif;

      if(!empty($this->comm_response_info) && preg_match('@\?code=(.*)&@i', $this->comm_response_info['url'], $auth_code)) :
         $this->auth_code = urldecode($auth_code[1]);
         $this->log('Setting auth code: "'.$this->auth_code.'"');

         return TRUE;
      endif;

      $this->errorsSet(array(
         'Failed to retreive auth code',
         'Endpoint: '.$comm_url,
         'REST method: GET',
         'REST args: '.((empty($comm_args)) ? 'NULL' : json_encode($comm_args)),
         'Response: '.$this->comm_response,
         'Response info: '.json_encode($this->comm_response_info),
      ), __LINE__, __METHOD__);

      return FALSE;
   }

   private function oAuthSetRestToken() {
      if(!empty($this->refresh_token)) :
         $comm_args = array(
            'grant_type' => 'refresh_token',
            'refresh_token' => $this->refresh_token,
            'client_id' => self::CLIENT_ID,
            'client_secret' => self::CLIENT_SECRET,
         );

         if(FALSE === $this->comm(NULL, 'POST', NULL, sprintf(self::ENDPOINT_ACCESS_TOKEN, http_build_query($comm_args)))) :
            return FALSE;
         endif;

         $this->log('Setting access token (via refresh): "'.$this->comm_response['access_token'].'"');
         $this->log('Setting refresh token (via refresh): "'.$this->comm_response['refresh_token'].'"');

         $this->access_token = $this->comm_response['access_token'];
         $this->refresh_token = $this->comm_response['refresh_token'];
         
         return TRUE;
      endif;

      if(FALSE === $this->oAuthSetAuthCode()) :
         return FALSE;
      endif;

      # Fetch access token
      $comm_args = array(
         'grant_type' => 'authorization_code',
         'code' => $this->auth_code,
         'client_id' => self::CLIENT_ID,
         'client_secret' => self::CLIENT_SECRET,
      );

      if(FALSE === $this->comm(NULL, 'POST', NULL, sprintf(self::ENDPOINT_ACCESS_TOKEN, http_build_query($comm_args)))) :
         return FALSE;
      endif;

      $this->log('Setting access token: "'.$this->comm_response['access_token'].'"');
      $this->log('Setting refresh token: "'.$this->comm_response['refresh_token'].'"');
         
      $this->access_token = $this->comm_response['access_token'];
      $this->refresh_token = $this->comm_response['refresh_token'];

      return TRUE;
   }

   private function searchBuildQuery($query_fields=array(), $select_args=array()) {
      $operator_groups = array('and', 'or', 'custom');

      # internal_field => bullhorn_field
      # This list could be greatly expanded...
      $possible_fields = array(
         'id' => 'id',
         'ID' => 'id',
         'first_name' => 'firstName',
         'firstName' => 'firstName',
         'last_name' => 'lastName',
         'email' => 'email',
         'is_deleted' => 'isDeleted',
         'isDeleted' => 'isDeleted',
      );

      if(empty($query_fields)) :
         $this->errorsSet('Query fields cannot be empty.', __LINE__, __METHOD__);
         return FALSE;
      endif;

      $valid_operator = FALSE;
      foreach($operator_groups as $operator) :
         if(!isset($query_fields[$operator]) || empty($query_fields[$operator]) || !is_array($query_fields[$operator])) :
            continue;
         endif;

         $valid_operator = TRUE;
         break;
      endforeach;

      if(FALSE === $valid_operator) :
         $this->errorsSet('Invalid query fields.', __LINE__, __METHOD__);
         return FALSE;
      endif;

      # Translate $select_args into BH field names
      foreach($select_args as $k => $v) :
         if(!isset($possible_fields[$v])) :
            unset($select_args[$operator][$k]);
            continue;
         endif;

         $select_args[$k] = $possible_fields[$v];
      endforeach;

      if(empty($select_args)) :
         $this->errorsSet('Select cannot be empty.', __LINE__, __METHOD__);
         return FALSE;
      endif;

      $return = array(
         'query' => '',
         'fields' => implode(',', $select_args),
      );

      foreach($query_fields as $operator_group => $operator_group_fields) :
         $return['query'] .= empty($return['query']) ? '' : ' AND ';

         if('custom' === $operator_group) :
            $return['query'] .= $operator_group_fields;
            continue;
         endif;
 
         $operator_fields = array();

         foreach($operator_group_fields as $operator_group_field => $operator_group_field_value) :
            if(!isset($possible_fields[$operator_group_field]) || in_array(trim($operator_group_field_value), array(NULL, ''))) :
               continue;
            endif;

            $operator_fields[] = $possible_fields[$operator_group_field].':'.$operator_group_field_value;
         endforeach;

         $return['query'] .= '('.implode(' '.strtoupper($operator_group).' ', $operator_fields).')';
      endforeach;

      if(empty($return['query'])) :
         $this->errorsSet('Invalid query fields', __LINE__, __METHOD__);
         return NULL;
      endif;

      return http_build_query($return);
   }
}

// End BullhornAPI class


Usage

Code: Select all

<?php
   require_once 'BullhornAPI.php';

   # ...

   if($_POST) :
      $bh_obj = new BullhornAPI();
      $candidate_data = $_POST;
      $form_status = NULL;

      # Validate resume upload
      if(NULL === $form_status) :
         if($_FILES) :
            if(FALSE === ($resume = validateUpload('resume'))) :
               $form_status = array('status' => 'error', 'message' => uploadError());
               unset($resume);
            endif;
         endif;
      endif;

      # Look for duplicate applicant
      if(NULL === $form_status) :
         $duplicate_candidates = $bh_obj->candidateFind(array('first_name' => $candidate_data['firstName'], 'last_name' => $candidate_data['lastName'], 'email' => $candidate_data['email']), TRUE);

         if(FALSE === $duplicate_candidates) :
            if(NULL === ($bh_error = $bh_obj->errorsGetLast())) :
               $bh_error = '('.__LINE__.') An unknown error occurred';
            endif;

            $form_status = array('status' => 'error', 'message' => $bh_error['message']);
         elseif(NULL !== $duplicate_candidates) :
            $duplicate_comment = 'DUP:'.implode(',', $duplicate_candidates);

            # "occupation" is the field name, Quick Notes is the field label...
            if(isset($candidate_data['occupation'])) :
               $candidate_data['occupation'] = trim($candidate_data['occupation'])."\n\n".$duplicate_comment;
            else :
               $candidate_data['occupation'] = $duplicate_comment;
            endif;
         endif;
      endif;

      # Create the candidate
      if(NULL === $form_status) :
         $candidate_data = array_merge($candidate_data, array(
            'firstName' => $candidate_data['firstName'],
            'lastName' => $candidate_data['lastName'],
            'name' => trim($candidate_data['firstName'].' '.$candidate_data['lastName']),
            'description' => 'Website applicant',
            'email' => $candidate_data['email'],
            'address' => array(
               'address1' => $candidate_data['address1'],
               'address2' => $candidate_data['address2'],
               'city' => $candidate_data['city'],
               'state' => $candidate_data['state'],
               'zip' => $candidate_data['zip'],
               'countryID' => $candidate_data['countryID'],
            ),
         ));

         # Ditch keys Bullhorn will complain about
         unset($candidate_data['address1']);
         unset($candidate_data['address2']);
         unset($candidate_data['city']);
         unset($candidate_data['state']);
         unset($candidate_data['zip']);
         unset($candidate_data['countryID']);

         if($has_resume) :
            $resume_filename = basename($resume['data']['tmp_name']);
            $resume_path = $resume['data']['tmp_name'];
         else :
            $resume_filename = $resume_path = NULL;
         endif;

         if(FALSE === ($candidate_id = $bh_obj->candidateCreate($candidate_data, $resume_path, $resume_filename))) :
            if(NULL === ($bh_error = $bh_obj->errorsGetLast())) :
               $bh_error = '('.__LINE__.') An unknown error occurred';
            endif;

            $form_status = array('status' => 'error', 'message' => $bh_error['message']);
         endif;
      endif;

      if(NULL === $form_status) :
         redirect('to/success/page');
      endif;

      # Do something with $form_status
   endif;

   # ...

Return to “REST API”

Who is online

Users browsing this forum: No registered users and 2 guests