getListeners('civi.api.prepare')) ) { Civi::dispatcher()->addListener( 'civi.api.prepare', ['CRM_TwingleCampaign_Utils_APIWrapper', 'PREPARE'], -100 ); } // Do only add listeners once if (!in_array( ["CRM_TwingleCampaign_Utils_APIWrapper", "RESPOND"], Civi::dispatcher()->getListeners('civi.api.respond') )) { Civi::dispatcher()->addListener( 'civi.api.respond', ['CRM_TwingleCampaign_Utils_APIWrapper', 'RESPOND'], -100 ); } } function twinglecampaign_civicrm_postSave_civicrm_case_type() { $twingle_project_case_custom_field = CustomField::fetch('twingle_project_case'); $newCaseType = json_decode($_POST['json'], True); $twingle_project_case_custom_field->addOptions( [$newCaseType['name'] => $newCaseType['title']] ); } /** * Implements hook_civicrm_postSave_Campaign(). * This function synchronizes TwingleProject campaigns between CiviCRM and * Twingle when they get created, edited or cloned. To prevent recursion a no * hook flag is getting used. * * @param $dao * * @throws \CiviCRM_API3_Exception */ function twinglecampaign_civicrm_postSave_civicrm_campaign($dao) { $twingle_project_campaign_type_id = _get_campaign_type_id_twingle_project(); $twingle_campaign_campaign_type_id = _get_campaign_type_id_twingle_campaign(); // If $campaign_type_id is a TwingleProject or TwingleCampaign campaign, // synchronize it if ( $dao->campaign_type_id == $twingle_project_campaign_type_id || $dao->campaign_type_id == $twingle_campaign_campaign_type_id ) { if (empty($_SESSION['CiviCRM']['de.forumzfd.twinglecampaign']['no_hook']) || $_SESSION['CiviCRM']['de.forumzfd.twinglecampaign']['no_hook'] != TRUE) { // If request is not an API-Call if ( ((isset($_GET['action']) && $_GET['action'] != 'create') || (isset($_POST['action']) && $_POST['action'] != 'create')) || (!isset($_GET['action']) && !isset($_POST['action'])) ) { // If the db transaction is still running, add a function to it that will // be called afterwards if (CRM_Core_Transaction::isActive()) { if (_validateAndSendInput($dao->id, $dao->campaign_type_id)) { CRM_Core_Transaction::addCallback( CRM_Core_Transaction::PHASE_POST_COMMIT, 'twinglecampaign_postSave_campaign_update_callback', [$dao->id, $dao->campaign_type_id] ); } } // If the transaction is already finished, call the function directly else { twinglecampaign_postSave_campaign_update_callback($dao->id, $dao->campaign_type_id); } } else { CRM_Core_Transaction::addCallback( CRM_Core_Transaction::PHASE_POST_COMMIT, 'twinglecampaign_postSave_campaign_update_callback', [$dao->id, $dao->campaign_type_id] ); } } } // Remove no hook flag unset($_SESSION['CiviCRM']['de.forumzfd.twinglecampaign']['no_hook']); } /** * ## postSave callback * This callback function synchronizes a recently updated TwingleProject or * creates a TwingleCampaign * * @param int $campaign_id * @param int $campaign_type_id * * @throws \CiviCRM_API3_Exception */ function twinglecampaign_postSave_campaign_update_callback( int $campaign_id, int $campaign_type_id ) { $twingle_project_campaign_type_id = _get_campaign_type_id_twingle_project(); $twingle_campaign_campaign_type_id = _get_campaign_type_id_twingle_campaign(); // Set $entity for $campaign_type_id if ($campaign_type_id == $twingle_project_campaign_type_id) { $entity = 'TwingleProject'; } elseif ($campaign_type_id == $twingle_campaign_campaign_type_id) { $entity = 'TwingleCampaign'; } else { Civi::log()->error( E::SHORT_NAME . " Update of TwingleCampaigns failed: Unknown campaign type (id: $campaign_type_id)" ); CRM_Core_Session::setStatus( E::ts('Unknown campaign type'), E::ts('Campaign type id: %1', [1 => $campaign_type_id]), error, [unique => TRUE] ); return; } if (isset($_POST['action'])) { if ($_POST['action'] == 'clone' && $entity == 'TwingleProject') { unset($_POST['action']); $result = civicrm_api3('TwingleProject', 'getsingle', ['id' => $campaign_id] ); $id = $result['id']; unset($result['id']); $project = new TwingleProject($result, $id); try { $project->clone(); } catch (Exception $e) { Civi::log()->error( E::LONG_NAME . ' could not clone ' . $entity . ': ' . $e->getMessage() ); CRM_Core_Session::setStatus( $e->getMessage(), E::ts("Campaign cloning failed"), error, [unique => TRUE] ); } } if ($_POST['action'] == 'clone' && $entity == 'TwingleCampaign') { unset($_POST['action']); try { civicrm_api3('TwingleCampaign', 'create', ['id' => $campaign_id, 'clone' => true] ); CRM_Utils_System::setUFMessage(E::ts('TwingleCampaign was cloned.')); } catch (CiviCRM_API3_Exception $e) { Civi::log()->error( 'twinglecampaign_postSave_callback ' . $e->getMessage() ); } } } // If a TwingleProject is getting saved elseif ($entity == 'TwingleProject') { // Synchronize all child TwingleCampaign campaigns try { civicrm_api3( 'TwingleCampaign', 'sync', ['parent_id' => $campaign_id]); } catch (CiviCRM_API3_Exception $e) { CRM_Core_Session::setStatus( $e->getMessage(), E::ts("TwingleCampaign update failed"), error, [unique => TRUE] ); Civi::log()->error( E::SHORT_NAME . ' Update of TwingleCampaigns failed: ' . $e->getMessage() ); } } else { try { civicrm_api3('TwingleCampaign', 'create', ['id' => $campaign_id, 'parent_id' => $_POST['parent_id']]); CRM_Utils_System::setUFMessage(E::ts('TwingleCampaign was saved.')); } catch (CiviCRM_API3_Exception $e) { Civi::log()->error( 'twinglecampaign_postSave_callback ' . $e->getMessage() ); } } } function _get_campaign_type_id_twingle_project() { return ExtensionCache::getInstance() ->getCampaignIds()['campaign_types']['twingle_project']['id']; } function _get_campaign_type_id_twingle_campaign() { return ExtensionCache::getInstance() ->getCampaignIds()['campaign_types']['twingle_campaign']['id']; } /** * Callback to sync a project after its creation. * * @param int $campaign_id */ function twinglecampaign_postSave_project_create_callback( int $campaign_id ) { try { civicrm_api3( 'TwingleProject', 'sync', ['id' => $campaign_id]); } catch (Exception $e) { CRM_Core_Session::setStatus( $e->getMessage(), E::ts("TwingleProject creation failed"), error, [unique => TRUE] ); Civi::log()->error( E::SHORT_NAME . ' Update of TwingleProject creation failed: ' . $e->getMessage() ); } } /** * First validate and then sends the input of this transaction to Twinge. * If the call to the Twingle API succeeded, this function returns TRUE; * * @param $id * @param $campaign_type_id * * @return bool * @throws \CiviCRM_API3_Exception * @throws \Exception */ function _validateAndSendInput($id, $campaign_type_id): bool { // Set callback for cloning if (isset($_POST['action'])) { CRM_Core_Transaction::addCallback( CRM_Core_Transaction::PHASE_POST_COMMIT, 'twinglecampaign_postSave_campaign_update_callback', [$id, $campaign_type_id] ); return FALSE; } if ($campaign_type_id == _get_campaign_type_id_twingle_project()) { // Instantiate project $project = new TwingleProject(); // Translate custom fields from $_POST $customFields = []; $customFieldsKeys = preg_grep('/^custom_/', array_keys($_POST)); foreach ($customFieldsKeys as $key) { $customFields[preg_replace('/_-?\d*$/', '', $key)] = $_POST[$key]; } $project->translateCustomFields( $customFields, TwingleProject::OUT ); TwingleProject::formatValues($customFields, TwingleProject::OUT); // Update project $project->update($customFields); // Set name if provided if (isset($_POST['title'])) { $project->setName($_POST['title']); } // Validate project values $validation = $project->validate(); // If the input is valid, send it to Twingle if ($validation['valid']) { // Try to retrieve twingleApi from cache or create a new $twingleApi = Civi::cache()->get('twinglecampaign_twingle_api'); if (NULL === $twingleApi) { try { $twingleApi = new TwingleApiCall(Civi::settings()->get('twingle_api_key')); } catch (Exception $e) { // Roll back transaction if input validation failed CRM_Core_Transaction::rollbackIfFalse(FALSE); CRM_Core_Session::setStatus( $e->getMessage(), E::ts("Could not retrieve Twingle API key"), error, [unique => TRUE] ); Civi::log()->error( E::SHORT_NAME . ' Could not retrieve Twingle API key: ' . $e->getMessage() ); } Civi::cache('long')->set('twinglecampaign_twingle_api', $twingleApi); } try { // Complement project values with values from Twingle if it has a // project_id if ($project->getProjectId()) { $project_from_twingle = $twingleApi->getProject($project->getProjectId()); $project->complement($project_from_twingle); } // If this campaign is just about to become created, add a callback to // sync it after the transaction has finished else { CRM_Core_Transaction::addCallback( CRM_Core_Transaction::PHASE_POST_COMMIT, 'twinglecampaign_postSave_project_create_callback', [$id] ); return FALSE; } // Push project require E::path() . '/api/v3/TwingleProject/Sync.php'; $result = _pushProjectToTwingle($project, $twingleApi, [], FALSE); if ($result['is_error'] != 0) { throw new \CiviCRM_API3_Exception($result['error_message']); } } catch (Exception $e) { // Roll back transaction if input validation failed CRM_Core_Transaction::rollbackIfFalse(FALSE); // Display and log error message CRM_Core_Session::setStatus( $e->getMessage(), E::ts("TwingleProject synchronization failed: %1", [1 => $e->getMessage()]), error, [unique => TRUE] ); Civi::log()->error( E::SHORT_NAME . ' TwingleProject synchronization failed: ' . $e->getMessage() ); // Push failed return FALSE; } // Push succeeded return TRUE; } // Display error message if validation failed else { // Roll back transaction if input validation failed CRM_Core_Transaction::rollbackIfFalse(FALSE); // Build error message $errorMessage = '