️ implement synchronisation of TwingleProject settings

This commit is contained in:
Marc Michalsky forumZFD 2021-04-12 10:11:06 +02:00
parent 0b1128fce5
commit 4dc3644bb3
Signed by untrusted user who does not match committer: marc.koch
GPG key ID: 12406554CFB028B9
3 changed files with 149 additions and 67 deletions

View file

@ -104,12 +104,11 @@ abstract class CRM_TwingleCampaign_BAO_Campaign {
return TRUE;
}
/**
* ## Update instance values
* This method updates the **$values** array of this instance with the values
* from the provided array if they are defined in
* *CRM/TwingleCampaign/resources/twingle_api_templates.json*
* *CRM/TwingleCampaign/resources/twingle_api_templates.php*
*
* @param array $values
* Array with values to update
@ -118,47 +117,33 @@ abstract class CRM_TwingleCampaign_BAO_Campaign {
// Update campaign values
$filter = Cache::getInstance()->getTemplates()[$this->className];
foreach ($values as $key => $value) {
if ($this->className == "TwingleProject" && $key == 'project_id') {
$this->values['id'] = $value;
}
elseif (in_array($key, $filter)) {
if ($this->in_array_r($key, $filter)) {
$this->values[$key] = $value;
}
elseif ($key == 'embed') {
self::setEmbedData($value);
}
elseif ($key == 'counter-url') {
self::setCounterUrl($value['url']);
}
}
}
/**
* ## Set embed data fields
* This method sets all embed data fields that are defined in
* *CRM/TwingleCampaign/resources/twingle_api_templates.json*
*
* @param array $embedData
* Array with embed data from Twingle API
* ## Complement campaign values
* Complement existing campaign values with new ones
* @param array $arrayToComplement
*/
public function setEmbedData(array $embedData) {
public function complement(array $arrayToComplement) {
$this->complement_r($this->values, $arrayToComplement);
$this->values = $arrayToComplement;
}
// Get all embed_data keys from template
$embed_data_keys = Cache::getInstance()
->getTemplates()['project_embed_data'];
// Transfer all embed_data values
foreach ($embed_data_keys as $key) {
if (array_key_exists($key, $embedData)) {
$this->values[$key] = $embedData[$key];
private function complement_r($orig, &$fill) {
foreach ($orig as $key => $value) {
if (is_array($value)) {
$this->complement_r($orig[$key], $fill[$key]);
} else {
$fill[$key] = $value;
}
}
}
public abstract function formatValues(array &$values, string $direction);
public static abstract function formatValues(array &$values, string $direction);
/**
* ## Translate array keys between CiviCRM Campaigns and Twingle

View file

@ -1,6 +1,5 @@
<?php
use CRM_TwingleCampaign_BAO_TwingleProject as TwingleProject;
use CRM_TwingleCampaign_ExtensionUtil as E;
@ -79,11 +78,41 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall {
*/
public function getProject(int $projectId = NULL): ?array {
$url = empty($projectId)
? $this->protocol . 'project' . $this->baseUrl . 'by-organisation/' . $this->organisationId
: $this->protocol . 'project' . $this->baseUrl . $projectId;
// If no project id is provided, return all projects
if (empty($projectId)) {
$response = [];
$projects = $this->curlGet($this->protocol . 'project' .
$this->baseUrl . 'by-organisation/' . $this->organisationId);
foreach ($projects as $project) {
$response[] = $this->getProject($project['id']);
}
return $response;
}
// If a project id is provided, return only one project
else {
return $this->curlGet($url);
// Get all general project information
$project = $this->curlGet($this->protocol . 'project' .
$this->baseUrl . $projectId);
// Get project options
$project['project_options'] = $this->getProjectOptions($projectId);
// Get project payment methods
$project['payment_methods'] =
$this->getProjectPaymentMethods($projectId);
// Set last update time
$project['last_update'] = max(
$project['last_update'],
$project['project_options']['last_update'],
$project['payment_methods']['updated_at']
);
unset($project['project_options']['last_update']);
unset($project['payment_methods']['updated_at']);
return $project;
}
}
/**
@ -92,30 +121,67 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall {
*
* Returns an array with all project values.
*
* @param TwingleProject $project
* The TwingleProject object that should get pushed to Twingle
* @param array $project
* The project values array that should get pushed to Twingle
*
* @return array
* @throws \Exception
*/
public function pushProject(TwingleProject &$project): array {
public function pushProject(array $project): array {
// Get only those values from the TwingleProject object which Twingle expects
$values = $project->export();
$projectOptions = $project['project_options'];
unset($project['project_options']);
$paymentMethods = $project['payment_methods'];
unset($project['payment_methods']);
// Prepare url for curl
if ($values['id']) {
$url = $this->protocol . 'project' . $this->baseUrl . $values['id'];
}
else {
try {
if (!isset($project['id'])) {
$url = $this->protocol . 'project' . $this->baseUrl . 'by-organisation/' .
$this->organisationId;
// Post project values
$updatedProject = $this->curlPost($url, $project);
$url = $this->protocol . 'project' . $this->baseUrl .
$updatedProject['id'];
}
else {
$url = $this->protocol . 'project' . $this->baseUrl . $project['id'];
// Post project values
$updatedProject = $this->curlPost($url, $project);
}
// Send curl and return result
return $this->curlPost($url, $values);
// Post project_options
$updatedProject['project_options'] =
$this->curlPost($url . '/options', $projectOptions);
// Post payment_methods
$this->curlPost($url . '/payment-methods', $paymentMethods);
$updatedProject['payment_methods'] =
$this->getProjectPaymentMethods($updatedProject['id']);
// Set last update time
$updatedProject['last_update'] = max(
$updatedProject['last_update'],
$updatedProject['project_options']['last_update'],
$updatedProject['payment_methods']['updated_at']
);
unset($updatedProject['project_options']['last_update']);
unset($updatedProject['payment_methods']['updated_at']);
return $updatedProject;
} catch (Exception $e) {
throw new Exception(
E::SHORT_NAME . 'Call to Twingle API failed: ' .
$e->getMessage()
);
}
}
/**
* ## Get event from Twingle
* Returns all events for the provided **$projectId** or a single event if an
@ -197,6 +263,33 @@ class CRM_TwingleCampaign_BAO_TwingleApiCall {
}
}
/**
* ## Get project options
* Gets all project options from the Twingle API
* @param $projectId
*
* @return array
* @throws \Exception
*/
public function getProjectOptions($projectId): array {
$url = $this->protocol . 'project' . $this->baseUrl . $projectId . '/options';
return $this->curlGet($url);
}
/**
* ## Get project payment methods
* Gets all project payment methods from the Twingle API
* @param $projectId
*
* @return array
* @throws \Exception
*/
public function getProjectPaymentMethods($projectId): array {
$url = $this->protocol . 'project' . $this->baseUrl . $projectId
. '/payment-methods';
return $this->curlGet($url);
}
/**
* ## Delete Project

View file

@ -189,11 +189,6 @@ function civicrm_api3_twingle_project_Sync(array $params): array {
$project = new TwingleProject($project_from_twingle);
try {
// Get embed data
$project->setEmbedData(
$twingleApi->getProjectEmbedData($project->getProjectId())
);
// If this is a test, do not make db changes
if (isset($params['is_test']) && $params['is_test']) {
$returnValues[$project->getId()] =
@ -231,14 +226,18 @@ function civicrm_api3_twingle_project_Sync(array $params): array {
$project = new TwingleProject($project_from_civicrm, $id);
// sync project
$result = _projectSync($project, $project_from_twingle, $twingleApi, $params);
if ($result['is_error'] != 0) {
$errors_occurred++;
$result = _projectSync(
$project,
$project_from_twingle,
$twingleApi,
$params);
if (!$result['is_error'] == 0) {
$errors[$result['id']] = $result['error_message'];
$returnValues[$project->getId()] =
$project->getResponse($result['error_message']);
}
else {
$returnValues[$project->getId()] = $result['values'];
$returnValues[$result['id']] = $result['values'][$result['id']];
}
break;
}
@ -284,9 +283,7 @@ function _updateProjectLocally(array $project_from_twingle,
try {
$project->update($project_from_twingle);
$project->setEmbedData(
$twingleApi->getProjectEmbedData($project->getProjectId())
);
// If this is a test, do not make db changes
if (array_key_exists('is_test', $params) && $params['is_test']) {
return civicrm_api3_create_success(
@ -346,7 +343,7 @@ function _pushProjectToTwingle(TwingleProject $project,
// Push project to Twingle
try {
$result = $twingleApi->pushProject($project);
$result = $twingleApi->pushProject($project->export());
} catch (Exception $e) {
Civi::log()->error(
E::LONG_NAME .
@ -363,11 +360,7 @@ function _pushProjectToTwingle(TwingleProject $project,
// Update local campaign with data returning from Twingle
if ($result) {
$project->update($result);
// Get embed data
try {
$project->setEmbedData(
$twingleApi->getProjectEmbedData($project->getProjectId())
);
// Create updated campaign
$project->create(TRUE);
$response = $project->getResponse('TwingleProject pushed to Twingle');
@ -432,6 +425,17 @@ function _projectSync(TwingleProject $project,
// If the CiviCRM TwingleProject campaign was changed, update the project
// on Twingle's side
elseif ($project_from_twingle['last_update'] < $project->lastUpdate()) {
// Make sure that the project hast a correct project_id. This is important
// to avoid an accidental cloning of project.
if (empty($project->getProjectId())) {
throw new \CiviCRM_API3_Exception(
'Missing project_id for project that is meant to get updated on Twingle side.');
}
// By merging the project values with the values coming from Twingle, we
// make sure that the project contains all values needed to get pushed
$project->complement($project_from_twingle);
return _pushProjectToTwingle($project, $twingleApi, $params);
}