/**
  * Merge 2 source records together, including all related data.
  *
  * @param Source  $prime   the record to merge into (will be preserved)
  * @param Source  $merge   the record to merge from (will be deleted)
  * @param array   $options (optional) options to use in merging conflicting data
  * @param boolean $commit  (optional)
  * @return boolean|string|array
  */
 public static function merge($prime, $merge, $options = array(), $commit = false)
 {
     self::$MERGE_OPTS = $options;
     self::$MERGE_RESULT = array('errs' => array(), 'prime' => array(), 'merge' => array(), 'moved' => array(), 'skipped' => array());
     // make sure we have fresh objects
     $prime->clearRelated();
     $merge->clearRelated();
     // start a transaction
     $conn = AIR2_DBManager::get_master_connection();
     $conn->beginTransaction();
     // run the merges
     try {
         self::merge_source($prime, $merge);
         self::merge_facts($prime, $merge);
         // remaining data produces no errors... so only run on commit
         if ($commit) {
             self::merge_easy($prime, $merge);
             self::combine_orgs($prime, $merge);
             self::combine_stat($prime, $merge);
         }
         // delete the merged source
         $merge->delete();
     } catch (Exception $e) {
         $conn->rollback();
         self::$MERGE_RESULT['fatal_error'] = $e->getMessage();
         return self::$MERGE_RESULT['fatal_error'];
     }
     // cache the merge result
     self::$MERGE_RESULT['result'] = $prime->toArray(true);
     // commit or rollback
     $errors = self::$MERGE_RESULT['errs'];
     if (count($errors) == 0 && $commit) {
         $conn->commit();
     } else {
         $conn->rollback();
         $prime->clearRelated();
         $prime->refresh();
         $merge->clearRelated();
         $merge->refresh();
     }
     // return errors or true on success
     if (count($errors) > 0) {
         return $errors;
     } else {
         return true;
     }
 }
 /**
  * Run a merge using the AIR2Merge library.
  *
  * @param array   $response_data
  */
 protected function run($response_data = array())
 {
     // turn off logging during the merge
     $was_logging_enabled = AIR2Logger::$ENABLE_LOGGING;
     AIR2Logger::$ENABLE_LOGGING = false;
     // run the merge and reset logging
     $type = $this->my_type;
     $errs = AIR2Merge::merge($this->prime, $this->merge, $this->ops, $this->commit_on_success);
     $result = AIR2Merge::get_result();
     AIR2Logger::$ENABLE_LOGGING = $was_logging_enabled;
     // what happened?
     $status = 200;
     if ($errs === true) {
         $response_data['success'] = true;
         $response_data['message'] = "Successfully merged {$type}s";
         // attach the "merged" object to data
         $response_data['ResultSource'] = $result['result'];
         air2_clean_radix($response_data['ResultSource'], $this->radix_whitelist);
         // attach ops used
         $response_data['op_prime'] = $result['prime'];
         $response_data['op_merge'] = $result['merge'];
         // log the merge
         if ($this->commit_on_success) {
             $this->log_activity($result, $response_data);
         }
     } elseif (is_string($errs)) {
         $response_data['success'] = false;
         $response_data['message'] = $errs;
         $status = 500;
     } else {
         $response_data['success'] = false;
         $response_data['message'] = "Unable to merge {$type}s";
         $response_data['errors'] = $errs;
         $status = 400;
         // attach ops used
         $response_data['op_prime'] = $result['prime'];
         $response_data['op_merge'] = $result['merge'];
     }
     // attach fact data
     $rs = AIR2_DBManager::get_connection()->fetchAll('select * from fact');
     $response_data['facts'] = array();
     foreach ($rs as $row) {
         $response_data['facts'][$row['fact_id']] = $row;
     }
     // respond with data
     $this->response($response_data, $status);
 }