diff --git a/CRM/TwingleCampaign/BAO/Campaign.php b/CRM/TwingleCampaign/BAO/Campaign.php
new file mode 100644
index 0000000..89fb9bf
--- /dev/null
+++ b/CRM/TwingleCampaign/BAO/Campaign.php
@@ -0,0 +1,624 @@
+className = get_class($this);
+
+ // If values come from CiviCRM Campaign API
+ if ($origin == self::CIVICRM) {
+
+ // Set id (campaign id) attribute
+ $this->id = $campaign['id'];
+
+ // Translate custom field names into Twingle field names
+ self::translateCustomFields($campaign, self::OUT);
+
+ // Translate keys and values
+ self::formatValues($campaign, self::OUT);
+ self::translateKeys($campaign, self::OUT);
+
+ }
+
+ // Set project values attribute
+ $this->values = $campaign;
+
+ }
+
+
+ /**
+ * Check if a campaign already exists and if so set attributes
+ * to the values of the existing campaign.
+ *
+ * @return bool
+ * Returns TRUE id the campaign already exists
+ *
+ * @throws CiviCRM_API3_Exception
+ *
+ * @throws Exception
+ */
+ public function exists() {
+
+ $result = [];
+ $single = FALSE;
+
+ // If there is more than one campaign for this entity, handle the duplicates
+ while (!$single) {
+ $result = civicrm_api3('Campaign', 'get', [
+ 'sequential' => 1,
+ 'is_active' => 1,
+ $this->id_custom_field => $this->values['id'],
+ ]);
+
+ if ($result['count'] > 1) {
+ // TODO: abort loop if function fails
+ self::handleDuplicates($result);
+ }
+ else {
+ $single = TRUE;
+ }
+ }
+
+ // If this campaign already exists, get its attributes
+ if ($result['count'] == 1) {
+
+ // Extract campaign values from result array
+ $values = $result['values'][0];
+
+ // Set id attribute
+ $this->id = $values['id'];
+
+ // Translate custom field names back
+ self::translateCustomFields($values, self::OUT);
+
+ // Translate keys from CiviCRM format to Twingle format
+ self::translateKeys($values, self::OUT);
+
+ // Set attributes to the values of the existing TwingleEvent campaign
+ // to reflect the state of the actual campaign in the database
+ $this->update($values);
+
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ /**
+ * Create the Campaign as a campaign in CiviCRM if it does not exist
+ *
+ * @param bool $is_test
+ * If true: don't do any changes
+ *
+ * @return array
+ * Returns a response array that contains title, id, project_id and status
+ *
+ * @throws CiviCRM_API3_Exception
+ * @throws Exception
+ */
+ public function create(bool $is_test = FALSE) {
+
+ // Create campaign only if it does not already exist
+ if (!$is_test) {
+
+ // Prepare project values for import into database
+ $values_prepared_for_import = $this->values;
+ self::formatValues(
+ $values_prepared_for_import,
+ self::IN
+ );
+ self::translateKeys(
+ $values_prepared_for_import,
+ self::IN
+ );
+ self::translateCustomFields(
+ $values_prepared_for_import,
+ self::IN
+ );
+
+ // Set id
+ $values_prepared_for_import['id'] = $this->id;
+
+ // Create campaign
+ $result = civicrm_api3('Campaign', 'create', $values_prepared_for_import);
+
+ // Update id
+ $this->id = $result['id'];
+
+ // Check if campaign was created successfully
+ if ($result['is_error'] == 0) {
+ $response = $this->getResponse("$this->className created");
+ }
+ else {
+ $response = $this->getResponse("$this->className creation failed");
+ }
+
+ }
+ // If this is a test, do not create campaign
+ else {
+ $response = $this->getResponse("$this->className not yet created");
+ }
+
+ return $response;
+ }
+
+
+ /**
+ * Update an existing campaign
+ *
+ * @param array $values
+ * Array with values to update
+ *
+ * @throws Exception
+ */
+ public function update(array $values) {
+
+ // Update campaign values
+ $this->values = array_merge($this->values, $values);
+ }
+
+
+ /**
+ * Instantiate an existing campaign by its id
+ *
+ * @param $id
+ *
+ * @return TwingleProject|TwingleEvent|TwingleCampaign|NULL
+ * @throws CiviCRM_API3_Exception
+ * @throws Exception
+ */
+ public static function fetch($id) {
+ $result = civicrm_api3('Campaign', 'getsingle', [
+ 'sequential' => 1,
+ 'id' => $id,
+ ]);
+
+ $twingle_campaign_types = Cache::getInstance()
+ ->getCampaigns()['campaign_types'];
+
+ $twingle_campaign_type_values = [];
+
+ foreach ($twingle_campaign_types as $twingle_campaign_type) {
+ $twingle_campaign_type_values[$twingle_campaign_type['name']] =
+ CampaignType::fetch($twingle_campaign_type['name'])->getValue();
+ }
+
+ switch ($result->values['campaign_type_id']) {
+ case $twingle_campaign_type_values['twingle_project']:
+ return new TwingleProject(
+ $result['values'],
+ self::CIVICRM
+ );
+ break;
+ case $twingle_campaign_type_values['twingle_event']:
+ return new TwingleEvent(
+ $result['values'],
+ self::CIVICRM
+ );
+ case $twingle_campaign_type_values['twingle_campaign']:
+ return new TwingleCampaign(
+ $result['values'],
+ self::CIVICRM
+ );
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+
+ /**
+ * Deactivate all duplicates of a project but the newest one
+ *
+ * @param array $result
+ * The $result array of a civicrm_api3-get-project call
+ *
+ * @throws CiviCRM_API3_Exception
+ */
+ protected function handleDuplicates(array $result) {
+
+ // Sort projects ascending by the value of the last_modified_date
+ uasort($result['values'], function ($a, $b) {
+ return $a['last_modified_date'] <=> $b['last_modified_date'];
+ });
+
+ // Delete the newest project from array to keep it active
+ array_shift($result['values']);
+
+ // deactivate the projects
+ foreach ($result['values'] as $p) {
+ self::deactivateById($p['id']);
+ }
+
+ }
+
+
+ /**
+ * Translate array keys between CiviCRM Campaigns and Twingle
+ *
+ * @param array $values
+ * array of which keys shall be translated
+ *
+ * @param string $direction
+ * Campaign::IN -> translate array keys from Twingle format into
+ * CiviCRM format
+ * Campaign::OUT -> translate array keys from CiviCRM format into
+ * Twingle format
+ *
+ * @throws Exception
+ */
+ public static function translateKeys(array &$values, string $direction) {
+
+ // Get translations for fields
+ $field_translations = Cache::getInstance()->getTranslations()['fields'];
+
+ // Set the direction of the translation
+ if ($direction == self::OUT) {
+ $field_translations = array_flip($field_translations);
+ }
+ // Throw error if $direction constant does not match IN or OUT
+ elseif ($direction != self::IN) {
+ throw new Exception(
+ "Invalid Parameter $direction for translateKeys()"
+ );
+ // TODO: use specific exception or create own
+ }
+
+ // Translate keys
+ foreach ($field_translations as $origin => $translation) {
+ $values[$translation] = $values[$origin];
+ unset($values[$origin]);
+ }
+ }
+
+
+ /**
+ * Translate values between CiviCRM Campaigns and Twingle
+ *
+ * @param array $values
+ * array of which values shall be translated
+ *
+ * @param string $direction
+ * Campaign::IN -> translate array values from Twingle to CiviCRM
+ * Campaign::OUT -> translate array values from CiviCRM to Twingle
+ *
+ * @throws Exception
+ */
+ private function formatValues(array &$values, string $direction) {
+
+ if ($direction == self::IN) {
+
+ // Change timestamp into DateTime string
+ if ($values['last_update']) {
+ $values['last_update'] =
+ self::getDateTime($values['last_update']);
+ }
+
+ // empty project_type to 'default'
+ if (!$values['type']) {
+ $values['type'] = 'default';
+ }
+ }
+ elseif ($direction == self::OUT) {
+
+ // Change DateTime string into timestamp
+ $values['last_update'] =
+ self::getTimestamp($values['last_update']);
+
+ // Default project_type to ''
+ $values['type'] = $values['type'] == 'default'
+ ? ''
+ : $values['type'];
+
+ // Cast project target to integer
+ $values['project_target'] = (int) $values['project_target'];
+
+ }
+ else {
+
+ throw new Exception(
+ "Invalid Parameter $direction for formatValues()"
+ );
+
+ }
+ }
+
+
+ /**
+ * Translate between Twingle field names and custom field names
+ *
+ * @param array $values
+ * array of which keys shall be translated
+ *
+ * @param string $direction
+ * Campaign::IN -> translate field names into custom field names
+ * Campaign::OUT -> translate custom field names into Twingle field
+ * names
+ *
+ */
+ public static function translateCustomFields(array &$values, string $direction) {
+
+ // Translate from Twingle field name to custom field name
+ if ($direction == self::IN) {
+
+ foreach (Cache::getInstance()
+ ->getCustomFieldMapping() as $field => $custom) {
+
+ if (array_key_exists(
+ str_replace(
+ 'twingle_project_',
+ '',
+ $field
+ ),
+ $values)
+ ) {
+
+ $values[$custom] = $values[str_replace(
+ 'twingle_project_',
+ '',
+ $field
+ )];
+
+ unset($values[str_replace(
+ 'twingle_project_',
+ '',
+ $field
+ )]
+ );
+ }
+ }
+ }
+ // Translate from custom field name to Twingle field name
+ elseif ($direction == self::OUT) {
+
+ foreach (Cache::getInstance()
+ ->getCustomFieldMapping() as $field => $custom) {
+
+ if (array_key_exists(
+ $custom,
+ $values
+ )
+ ) {
+ $values[str_replace(
+ 'twingle_project_',
+ '',
+ $field
+ )] = $values[$custom];
+ unset($values[$custom]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set embed data fields
+ *
+ * @param array $embedData
+ * Array with embed data from Twingle API
+ */
+ public function setEmbedData(array $embedData) {
+
+ // 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) {
+ $this->values[$key] = htmlspecialchars($embedData[$key]);
+ }
+ }
+
+ /**
+ * Set counter url
+ *
+ * @param String $counterUrl
+ * URL of the counter
+ */
+ public function setCounterUrl(string $counterUrl) {
+ $this->values['counter'] = $counterUrl;
+ }
+
+ /**
+ * Deactivate this Campaign campaign
+ *
+ * @return bool
+ * TRUE if deactivation was successful
+ *
+ * @throws CiviCRM_API3_Exception
+ */
+ public function deactivate() {
+
+ return self::deactivateByid($this->id);
+
+ }
+
+ /**
+ * Deactivate a Campaign campaign by ID
+ *
+ * @param $id
+ * ID of the campaign that should get deactivated
+ *
+ * @return bool
+ * TRUE if deactivation was successful
+ *
+ * @throws CiviCRM_API3_Exception
+ */
+ public static function deactivateById($id) {
+
+ $result = civicrm_api3('Campaign', 'getsingle', [
+ 'id' => $id,
+ 'sequential' => 1,
+ ]);
+
+ $result = civicrm_api3('Campaign', 'create', [
+ 'title' => $result['title'],
+ 'id' => $id,
+ 'is_active' => '0',
+ ]);
+
+ // Return TRUE if the campaign was deactivated successfully
+ if ($result['is_error'] == 0) {
+ return TRUE;
+ }
+ // Return FALSE if deactivation failed
+ else {
+ return FALSE;
+ }
+
+ }
+
+
+ /**
+ * Get a response that describes the status of a Campaign
+ *
+ * @param string $status
+ * status of the Campaign you want the response for
+ *
+ * @return array
+ * Returns a response array that contains title, id, project_id and status
+ */
+ public function getResponse(string $status) {
+ return [
+ 'title' => $this->values['name'],
+ 'id' => (int) $this->id,
+ 'project_id' => (int) $this->values['id'],
+ 'project_type' => $this->values['type'],
+ 'status' => $status,
+ ];
+ }
+
+
+ /**
+ * Validates $input to be either a DateTime string or an Unix timestamp
+ *
+ * @param $input
+ * Pass a DateTime string or a Unix timestamp
+ *
+ * @return int
+ * Returns a Unix timestamp or NULL if $input is invalid
+ */
+ public static function getTimestamp($input) {
+
+ // Check whether $input is a Unix timestamp
+ if (
+ $dateTime = DateTime::createFromFormat('U', $input)
+ ) {
+ return $input;
+ }
+ // ... or a DateTime string
+ elseif (
+ $dateTime = DateTime::createFromFormat('Y-m-d H:i:s', $input)
+ ) {
+ return $dateTime->getTimestamp();
+ }
+ // ... or invalid
+ else {
+ return NULL;
+ }
+
+ }
+
+
+ /**
+ * Validates $input to be either a DateTime string or an Unix timestamp
+ *
+ * @param $input
+ * Pass a DateTime string or a Unix timestamp
+ *
+ * @return string
+ * Returns a DateTime string or NULL if $input is invalid
+ */
+ public static function getDateTime($input) {
+
+ // Check whether $input is a Unix timestamp
+ if (
+ $dateTime = DateTime::createFromFormat('U', $input)
+ ) {
+ return $dateTime->format('Y-m-d H:i:s');
+ }
+ // ... or a DateTime string
+ elseif (
+ $dateTime = DateTime::createFromFormat('Y-m-d H:i:s', $input)
+ ) {
+ return $input;
+ }
+ // ... or invalid
+ else {
+ return NULL;
+ }
+
+ }
+
+
+ /**
+ * Return a timestamp of the last update of the Campaign
+ *
+ * @return int|null
+ */
+ public function lastUpdate() {
+
+ return self::getTimestamp($this->values['last_update']);
+ }
+
+
+ /**
+ * Returns the project_id of a Campaign
+ *
+ * @return int
+ */
+ public function getProjectId() {
+ return $this->values['id'];
+ }
+
+
+ /**
+ * @return mixed
+ */
+ public function getId() {
+ return $this->id;
+ }
+
+}
diff --git a/CRM/TwingleCampaign/BAO/CampaignType.php b/CRM/TwingleCampaign/BAO/CampaignType.php
index 261fd75..36f6ed3 100644
--- a/CRM/TwingleCampaign/BAO/CampaignType.php
+++ b/CRM/TwingleCampaign/BAO/CampaignType.php
@@ -51,8 +51,8 @@ class CampaignType {
$this->value = array_column($this->results['values'], 'value')[0];
if ($this->results['is_error'] == 0) {
- \Civi::log()->info("Twingle Extension has created a new campaign type.\n
- label: $this->label\n
+ \Civi::log()->info("Twingle Extension has created a new campaign type.
+ label: $this->label
name: $this->name"
);
}
@@ -104,12 +104,12 @@ class CampaignType {
}
/**
- * @param $name
+ * @param string $name
*
* @return \CRM\TwingleCampaign\BAO\CampaignType|null
* @throws \CiviCRM_API3_Exception
*/
- public static function fetch($name) {
+ public static function fetch(string $name) {
$campaign_type = civicrm_api3(
'OptionValue',
'get',
diff --git a/CRM/TwingleCampaign/BAO/CustomField.php b/CRM/TwingleCampaign/BAO/CustomField.php
index a73ea81..ebc5868 100644
--- a/CRM/TwingleCampaign/BAO/CustomField.php
+++ b/CRM/TwingleCampaign/BAO/CustomField.php
@@ -89,10 +89,10 @@ class CustomField {
// Log field creation
if ($this->result['is_error'] == 0) {
- \Civi::log()->info("Twingle Extension has created a new custom field.\n
- label: $this->label\n
- name: $this->name\n
- id: $this->id\n
+ \Civi::log()->info("Twingle Extension has created a new custom field.
+ label: $this->label
+ name: $this->name
+ id: $this->id
group: $this->custom_group_id"
);
}
@@ -224,10 +224,10 @@ class CustomField {
// Check if custom field was deleted successfully
if ($this->result['is_error'] == 0) {
- \Civi::log()->info("Twingle Extension has deleted custom field.\n
- label: $this->label\n
- name: $this->name\n
- id: $this->id\n
+ \Civi::log()->info("Twingle Extension has deleted custom field.
+ label: $this->label
+ name: $this->name
+ id: $this->id
group: $this->custom_group_id"
);
}
diff --git a/CRM/TwingleCampaign/BAO/CustomGroup.php b/CRM/TwingleCampaign/BAO/CustomGroup.php
index 87d2238..91c7529 100644
--- a/CRM/TwingleCampaign/BAO/CustomGroup.php
+++ b/CRM/TwingleCampaign/BAO/CustomGroup.php
@@ -49,11 +49,11 @@ class CustomGroup {
$this->id = $this->results['id'];
if ($this->results['is_error'] == 0) {
- \Civi::log()->info("Twingle Extension has created a new custom group.\n
- title: $this->title\n
- name: $this->name\n
- extends: $this->extends\n
- id: $this->id\n
+ \Civi::log()->info("Twingle Extension has created a new custom group.
+ title: $this->title
+ name: $this->name
+ extends: $this->extends
+ id: $this->id
column_value: $this->extends_entity_column_value"
);
}
@@ -134,10 +134,10 @@ class CustomGroup {
);
if ($this->results['is_error'] == 0) {
- \Civi::log()->info("Twingle Extension has deleted custom group.\n
- title: $this->title\n
- name: $this->name\n
- extends: $this->extends\n
+ \Civi::log()->info("Twingle Extension has deleted custom group.
+ title: $this->title
+ name: $this->name
+ extends: $this->extends
id : $this->id"
);
diff --git a/CRM/TwingleCampaign/BAO/TwingleCampaign.php b/CRM/TwingleCampaign/BAO/TwingleCampaign.php
index b6ebe28..749d6c4 100644
--- a/CRM/TwingleCampaign/BAO/TwingleCampaign.php
+++ b/CRM/TwingleCampaign/BAO/TwingleCampaign.php
@@ -4,6 +4,6 @@
namespace CRM\TwingleCampaign\BAO;
-class TwingleCampaign {
+class TwingleCampaign extends Campaign {
}
\ No newline at end of file
diff --git a/CRM/TwingleCampaign/BAO/TwingleEvent.php b/CRM/TwingleCampaign/BAO/TwingleEvent.php
index 1c21ce1..c086d5c 100644
--- a/CRM/TwingleCampaign/BAO/TwingleEvent.php
+++ b/CRM/TwingleCampaign/BAO/TwingleEvent.php
@@ -3,7 +3,156 @@
namespace CRM\TwingleCampaign\BAO;
+use Civi;
+use CRM\TwingleCampaign\Utils\ExtensionCache as Cache;
+use CRM_TwingleCampaign_ExtensionUtil as E;
+use CRM_Utils_Array;
+use DateTime;
+use CRM\TwingleCampaign\BAO\CustomField as CustomField;
+use Exception;
+use CiviCRM_API3_Exception;
-class TwingleEvent {
+include_once E::path() . '/CRM/TwingleCampaign/BAO/CustomField.php';
-}
\ No newline at end of file
+
+class TwingleEvent extends Campaign {
+
+ /**
+ * TwingleEvent constructor.
+ *
+ * @param array $event
+ * Result array of Twingle API call to
+ * https://project.twingle.de/api/$project_id/event
+ *
+ * @param string $origin
+ * Origin of the arrays. It can be one of two constants:
+ * TwingleEvent::TWINGLE|CIVICRM
+ *
+ * @throws Exception
+ */
+ public function __construct(array $event, string $origin) {
+ parent::__construct($event, $origin);
+
+ $this->className = get_class($this);
+
+ // Add value for campaign type
+ $event['campaign_type_id'] = 'twingle_event';
+
+ // Get custom field name for event_id
+ $this->id_custom_field = Cache::getInstance()
+ ->getCustomFieldMapping()['twingle_event_id'];
+
+ }
+
+
+ /**
+ * Translate values between CiviCRM Campaigns and Twingle
+ *
+ * @param array $values
+ * array of which values shall be translated
+ *
+ * @param string $direction
+ * TwingleEvent::IN -> translate array values from Twingle to CiviCRM
+ * TwingleEvent::OUT -> translate array values from CiviCRM to Twingle
+ *
+ * @throws Exception
+ */
+ private function formatValues(array &$values, string $direction) {
+
+ if ($direction == self::IN) {
+
+ // Change timestamp into DateTime string
+ if ($values['last_update']) {
+ $values['last_update'] =
+ self::getDateTime($values['last_update']);
+ }
+
+ // empty project_type to 'default'
+ if (!$values['type']) {
+ $values['type'] = 'default';
+ }
+ }
+ elseif ($direction == self::OUT) {
+
+ // Change DateTime string into timestamp
+ $values['last_update'] =
+ self::getTimestamp($values['last_update']);
+
+ // Default project_type to ''
+ $values['type'] = $values['type'] == 'default'
+ ? ''
+ : $values['type'];
+
+ // Cast project target to integer
+ $values['project_target'] = (int) $values['project_target'];
+
+ }
+ else {
+
+ throw new Exception(
+ "Invalid Parameter $direction for formatValues()"
+ );
+
+ }
+ }
+
+
+ /**
+ * Set embed data fields
+ *
+ * @param array $embedData
+ * Array with embed data from Twingle API
+ */
+ public function setEmbedData(array $embedData) {
+
+ // Get all embed_data keys from template
+ $embed_data_keys = Cache::getInstance()
+ ->getTemplates()['event_embed_data'];
+
+ // Transfer all embed_data values
+ foreach ($embed_data_keys as $key) {
+ $this->values[$key] = htmlspecialchars($embedData[$key]);
+ }
+ }
+
+
+ /**
+ * Get a response that describes the status of a TwingleEvent
+ *
+ * @param string $status
+ * status of the TwingleEvent you want the response for
+ *
+ * @return array
+ * Returns a response array that contains title, id, project_id and status
+ */
+ public function getResponse(string $status) {
+ return [
+ 'title' => $this->values['name'],
+ 'id' => (int) $this->id,
+ 'event_id' => (int) $this->values['id'],
+ 'project_id' => (int) $this->values['project_id'],
+ 'status' => $status,
+ ];
+ }
+
+
+ /**
+ * Returns the project_id of a TwingleEvent
+ *
+ * @return int
+ */
+ public function getProjectId() {
+ return (int) $this->values['project_id'];
+ }
+
+
+ /**
+ * Returns the event_id of a TwingleEvent
+ *
+ * @return int
+ */
+ public function getEventId() {
+ return (int) $this->values['id'];
+ }
+
+}
diff --git a/CRM/TwingleCampaign/BAO/TwingleProject.php b/CRM/TwingleCampaign/BAO/TwingleProject.php
index fd8796c..abb2f1f 100644
--- a/CRM/TwingleCampaign/BAO/TwingleProject.php
+++ b/CRM/TwingleCampaign/BAO/TwingleProject.php
@@ -10,24 +10,7 @@ use Exception;
use CiviCRM_API3_Exception;
-class TwingleProject {
-
- // IN means: heading into CiviCRM database
- public const IN = 'IN';
-
- // OUT means: coming from the CiviCRM database
- public const OUT = 'OUT';
-
- public const CIVICRM = 'CIVICRM';
-
- public const TWINGLE = 'TWINGLE';
-
- private static $bInitialized = FALSE;
-
- private $id;
-
- private $values;
-
+class TwingleProject extends Campaign {
/**
* TwingleProject constructor.
@@ -43,101 +26,17 @@ class TwingleProject {
* @throws Exception
*/
public function __construct(array $project, string $origin) {
+ parent::__construct($project, $origin);
- // If values come from CiviCRM Campaign API
- if ($origin == self::CIVICRM) {
-
- // Set id (campaign id) attribute
- $this->id = $project['id'];
-
- // Translate custom field names into Twingle field names
- self::translateCustomFields($project, self::OUT);
-
- // Translate keys and values
- self::formatValues($project, self::OUT);
- self::translateKeys($project, self::OUT);
-
- }
+ $this->className = get_class($this);
// Add value for campaign type
- $project['campaign_type_id'] = 'twingle_project';
+ $this->values['campaign_type_id'] = 'twingle_project';
- // Set project values attribute
- $this->values = $project;
- }
+ // Get custom field name for project_id
+ $this->id_custom_field = Cache::getInstance()
+ ->getCustomFieldMapping()['twingle_project_id'];
-
- /**
- * Create the TwingleProject as a campaign in CiviCRM if it does not exist
- *
- * @param bool $is_test
- * If true: don't do any changes
- *
- * @return array
- * Returns a response array that contains title, id, project_id and status
- *
- * @throws CiviCRM_API3_Exception
- * @throws Exception
- */
- public function create(bool $is_test = FALSE) {
-
- // Create campaign only if it does not already exist
- if (!$is_test) {
-
- // Prepare project values for import into database
- $values_prepared_for_import = $this->values;
- self::formatValues(
- $values_prepared_for_import,
- self::IN
- );
- self::translateKeys(
- $values_prepared_for_import,
- self::IN
- );
- self::translateCustomFields(
- $values_prepared_for_import,
- self::IN
- );
-
- // Set id
- $values_prepared_for_import['id'] = $this->id;
-
- // Create campaign
- $result = civicrm_api3('Campaign', 'create', $values_prepared_for_import);
-
- // Update id
- $this->id = $result['id'];
-
- // Check if campaign was created successfully
- if ($result['is_error'] == 0) {
- $response = $this->getResponse('TwingleProject created');
- }
- else {
- $response = $this->getResponse('TwingleProject creation failed');
- }
-
- }
- // If this is a test, do not create campaign
- else {
- $response = $this->getResponse('TwingleProject not yet created');
- }
-
- return $response;
- }
-
-
- /**
- * Update an existing project
- *
- * @param array $values
- * Array with values to update
- *
- * @throws Exception
- */
- public function update(array $values) {
-
- // Update project values
- $this->values = array_merge($this->values, $values);
}
@@ -156,7 +55,7 @@ class TwingleProject {
self::formatValues($values, self::OUT);
// Get template for project
- $project = self::$templates['project'];
+ $project = Cache::getInstance()->getTemplates()['project'];
// Replace array items which the Twingle API does not expect
foreach ($values as $key => $value) {
@@ -169,158 +68,6 @@ class TwingleProject {
}
- /**
- * Check if a TwingleProject campaign already exists and if so set attributes
- * to the values of the existing campaign.
- *
- * @return bool
- * Returns TRUE id the TwingleProject campaign already exists
- *
- * @throws CiviCRM_API3_Exception
- *
- * @throws Exception
- */
- public function exists() {
-
- $result = [];
- $single = FALSE;
-
- // Get custom field name for project_id
- $cf_project_id = Cache::getInstance()
- ->getCustomFieldMapping()['twingle_project_id'];
-
- // If there is more than one campaign for a project, handle the duplicates
- while (!$single) {
- $result = civicrm_api3('Campaign', 'get', [
- 'sequential' => 1,
- 'is_active' => 1,
- $cf_project_id => $this->values['id'],
- ]);
-
- if ($result['count'] > 1) {
- // TODO: abort loop if function fails
- TwingleProject::handleDuplicates($result);
- }
- else {
- $single = TRUE;
- }
- }
-
- // If the campaign for the TwingleProject already exists, some of the
- // project's attributes must be updated from the campaign
- if ($result['count'] == 1) {
-
- // Extract project values from result array
- $values = $result['values'][0];
-
- // Set campaign id attribute
- $this->id = $values['id'];
-
- // Translate custom field names back
- self::translateCustomFields($values, self::OUT);
-
- // Translate keys from CiviCRM format to Twingle format
- self::translateKeys($values, self::OUT);
-
- // Set attributes to the values of the existing TwingleProject campaign
- // to reflect the state of the actual campaign in the database
- $this->update($values);
-
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
-
- /**
- * Instantiate an existing project by campaign id
- *
- * @param $id
- *
- * @return TwingleProject
- * @throws CiviCRM_API3_Exception
- * @throws Exception
- */
- public static function fetch($id) {
- $result = civicrm_api3('Campaign', 'getsingle', [
- 'sequential' => 1,
- 'id' => $id,
- ]);
-
- return new TwingleProject(
- $result['values'],
- self::CIVICRM
- );
- }
-
-
- /**
- * Deactivate all duplicates of a project but the newest one
- *
- * @param array $result
- * The $result array of a civicrm_api3-get-project call
- *
- * @throws CiviCRM_API3_Exception
- */
- private function handleDuplicates(array $result) {
-
- // Sort projects ascending by the value of the last_modified_date
- uasort($result['values'], function ($a, $b) {
- return $a['last_modified_date'] <=> $b['last_modified_date'];
- });
-
- // Delete the newest project from array to keep it active
- array_shift($result['values']);
-
- // deactivate the projects
- foreach ($result['values'] as $p) {
- self::deactivateById($p['id']);
- }
-
- }
-
-
- /**
- * Translate array keys between CiviCRM Campaigns and Twingle
- *
- * @param array $values
- * array of which keys shall be translated
- *
- * @param string $direction
- * TwingleProject::IN -> translate array keys from Twingle format into
- * CiviCRM format
- * TwingleProject::OUT -> translate array keys from CiviCRM format into
- * Twingle format
- *
- * @throws Exception
- */
- public static function translateKeys(array &$values, string $direction) {
-
- // Get translations for fields
- $field_translations = Cache::getInstance()->getTranslations()['fields'];
-
- // Set the direction of the translation
- if ($direction == self::OUT) {
- $field_translations = array_flip($field_translations);
- }
- // Throw error if $direction constant does not match IN or OUT
- elseif ($direction != self::IN) {
- throw new Exception(
- "Invalid Parameter $direction for translateKeys()"
- );
- // TODO: use specific exception or create own
- }
-
- // Translate keys
- foreach ($field_translations as $origin => $translation) {
- $values[$translation] = $values[$origin];
- unset($values[$origin]);
- }
- }
-
-
/**
* Translate values between CiviCRM Campaigns and Twingle
*
@@ -373,72 +120,6 @@ class TwingleProject {
}
- /**
- * Translate between Twingle field names and custom field names
- *
- * @param array $values
- * array of which keys shall be translated
- *
- * @param string $direction
- * TwingleProject::IN -> translate field names into custom field names
- * TwingleProject::OUT -> translate custom field names into Twingle field
- * names
- *
- */
- public static function translateCustomFields(array &$values, string $direction) {
-
- // Translate from Twingle field name to custom field name
- if ($direction == self::IN) {
-
- foreach (Cache::getInstance()
- ->getCustomFieldMapping() as $field => $custom) {
-
- if (array_key_exists(
- str_replace(
- 'twingle_project_',
- '',
- $field
- ),
- $values)
- ) {
-
- $values[$custom] = $values[str_replace(
- 'twingle_project_',
- '',
- $field
- )];
-
- unset($values[str_replace(
- 'twingle_project_',
- '',
- $field
- )]
- );
- }
- }
- }
- // Translate from custom field name to Twingle field name
- elseif ($direction == self::OUT) {
-
- foreach (Cache::getInstance()
- ->getCustomFieldMapping() as $field => $custom) {
-
- if (array_key_exists(
- $custom,
- $values
- )
- ) {
- $values[str_replace(
- 'twingle_project_',
- '',
- $field
- )] = $values[$custom];
- unset($values[$custom]);
- }
- }
- }
- }
-
/**
* Set embed data fields
*
@@ -481,41 +162,6 @@ class TwingleProject {
}
- /**
- * Deactivate a TwingleProject campaign by ID
- *
- * @param $id
- * ID of the TwingleProject campaign that should get deactivated
- *
- * @return bool
- * TRUE if deactivation was successful
- *
- * @throws CiviCRM_API3_Exception
- */
- public static function deactivateById($id) {
-
- $result = civicrm_api3('Campaign', 'getsingle', [
- 'id' => $id,
- 'sequential' => 1,
- ]);
-
- $result = civicrm_api3('Campaign', 'create', [
- 'title' => $result['title'],
- 'id' => $id,
- 'is_active' => '0',
- ]);
-
- // Return TRUE if TwingleProject campaign was deactivated successfully
- if ($result['is_error'] == 0) {
- return TRUE;
- }
- // Return FALSE if deactivation failed
- else {
- return FALSE;
- }
-
- }
-
/**
* Get a response that describes the status of a TwingleProject
@@ -537,94 +183,13 @@ class TwingleProject {
}
- /**
- * Validates $input to be either a DateTime string or an Unix timestamp
- *
- * @param $input
- * Pass a DateTime string or a Unix timestamp
- *
- * @return int
- * Returns a Unix timestamp or NULL if $input is invalid
- */
- public static function getTimestamp($input) {
-
- // Check whether $input is a Unix timestamp
- if (
- $dateTime = DateTime::createFromFormat('U', $input)
- ) {
- return $input;
- }
- // ... or a DateTime string
- elseif (
- $dateTime = DateTime::createFromFormat('Y-m-d H:i:s', $input)
- ) {
- return $dateTime->getTimestamp();
- }
- // ... or invalid
- else {
- return NULL;
- }
-
- }
-
-
- /**
- * Validates $input to be either a DateTime string or an Unix timestamp
- *
- * @param $input
- * Pass a DateTime string or a Unix timestamp
- *
- * @return string
- * Returns a DateTime string or NULL if $input is invalid
- */
- public static function getDateTime($input) {
-
- // Check whether $input is a Unix timestamp
- if (
- $dateTime = DateTime::createFromFormat('U', $input)
- ) {
- return $dateTime->format('Y-m-d H:i:s');
- }
- // ... or a DateTime string
- elseif (
- $dateTime = DateTime::createFromFormat('Y-m-d H:i:s', $input)
- ) {
- return $input;
- }
- // ... or invalid
- else {
- return NULL;
- }
-
- }
-
-
- /**
- * Return a timestamp of the last update of the TwingleProject
- *
- * @return int|null
- */
- public function lastUpdate() {
-
- return self::getTimestamp($this->values['last_update']);
- }
-
-
/**
* Returns the project_id of a TwingleProject
*
* @return int
*/
public function getProjectId() {
- return $this->values['id'];
- }
-
-
- /**
- * @return mixed
- */
- public function getId() {
- return $this->id;
+ return (int) $this->values['id'];
}
}
diff --git a/CRM/TwingleCampaign/resources/twingle_api_templates.json b/CRM/TwingleCampaign/resources/twingle_api_templates.json
index 2e5fe85..620ed40 100644
--- a/CRM/TwingleCampaign/resources/twingle_api_templates.json
+++ b/CRM/TwingleCampaign/resources/twingle_api_templates.json
@@ -19,5 +19,16 @@
"eventlist"
],
"event": [
+ ],
+ "event_embed_data": [
+ "page",
+ "eventpage",
+ "widget",
+ "form",
+ "widget-single",
+ "form-single",
+ "eventall",
+ "eventlist",
+ "eventeditcreate"
]
}
\ No newline at end of file
diff --git a/api/v3/TwingleSync/BAO/TwingleApiCall.php b/api/v3/TwingleSync/BAO/TwingleApiCall.php
index d71ad4e..9ee3b30 100644
--- a/api/v3/TwingleSync/BAO/TwingleApiCall.php
+++ b/api/v3/TwingleSync/BAO/TwingleApiCall.php
@@ -54,7 +54,8 @@ class TwingleApiCall {
* If $id parameter is empty, this function returns all projects for all
* organisations this API key is assigned to.
*
- * TODO: Keys can only get assigned to one organisation. Save multiple keys in settings instead.
+ * TODO: Keys can only get assigned to one organisation. Save multiple keys
+ * in settings instead.
*
* If $id parameter is given, this function returns a single project.
*
@@ -184,7 +185,7 @@ class TwingleApiCall {
$result['status'] = $result['status'] == 'TwingleProject created'
? 'TwingleProject updated'
: 'TwingleProject Update failed';
- } catch (Exception $e){
+ } catch (Exception $e) {
// Log Exception
Civi::log()->error(
"Could not update TwingleProject campaign: $e->getMessage()"
@@ -304,8 +305,98 @@ class TwingleApiCall {
}
+ /**
+ * @param array $values
+ * @param bool $isTest
+ *
+ * @return array | NULL
+ * @throws \CiviCRM_API3_Exception
+ */
+ public function syncEvent(array $values, bool $isTest) {
+ // If $event is an array
+ if (is_array($values)) {
- public function updateEvent() {
+ // Instantiate TwingleEvent
+ try {
+ $event = new TwingleEvent(
+ $values,
+ TwingleEvent::TWINGLE
+ );
+ } catch (Exception $e) {
+
+ // Log Exception
+ Civi::log()->error(
+ "Failed to instantiate TwingleEvent: $e->getMessage()"
+ );
+
+ // Return result array with error description
+ return [
+ "title" => $values['description'],
+ "event_id" => (int) $values['id'],
+ "project_id" => (int) $values['id'],
+ "status" =>
+ "Failed to instantiate TwingleEvent: $e->getMessage()",
+ ];
+ }
+
+ // Check if the TwingleProject campaign already exists
+ if (!$event->exists()) {
+
+ // ... if not, get embed data and create project
+ try {
+ $this->getEmbedData($event); // TODO: !
+ $result = $event->create($is_test);
+ } catch (Exception $e) {
+
+ // Log Exception
+ Civi::log()->error(
+ "Could not create campaign from TwingleEvent: $e->getMessage()"
+ );
+
+ // Return result array with error description
+ return [
+ "title" => $values['description'],
+ "event_id" => (int) $values['id'],
+ "project_id" => (int) $values['id'],
+ "Could not create campaign from TwingleEvent: $e->getMessage()",
+ ];
+ }
+ }
+ else {
+ $result = $event->getResponse('TwingleEvent exists');
+
+ // If Twingle's version of the event is newer than the CiviCRM
+ // TwingleEvent campaign update the campaign
+ if ($values['last_update'] > $event->lastUpdate()) {
+ try {
+ $event->update($values);
+ $this->getEmbedData($event); // TODO: !
+ $result = $event->create();
+ $result['status'] = $result['status'] == 'TwingleEvent created'
+ ? 'TwingleEvent updated'
+ : 'TwingleEvent Update failed';
+ } catch (Exception $e) {
+ // Log Exception
+ Civi::log()->error(
+ "Could not update TwingleEvent campaign: $e->getMessage()"
+ );
+ // Return result array with error description
+ $result = $event->getResponse(
+ "Could not update TwingleProject campaign: $e->getMessage()"
+ );
+ }
+ }
+ elseif ($result['status'] == 'TwingleEvent exists') {
+ $result = $event->getResponse('TwingleEvent up to date');
+ }
+ }
+
+ // Return a response of the synchronization
+ return $result;
+ }
+ else {
+ return NULL;
+ }
}
@@ -382,10 +473,10 @@ class TwingleApiCall {
*/
private function getResultArray($values, $status) {
return [
- "title" => $values['name'],
- "project_id" => (int) $values['id'],
+ "title" => $values['name'],
+ "project_id" => (int) $values['id'],
"project_type" => $values['project_type'],
- "status" => $status
+ "status" => $status,
];
}
diff --git a/api/v3/TwingleSync/Post.php b/api/v3/TwingleSync/Post.php
index 0b214dc..1bf8264 100644
--- a/api/v3/TwingleSync/Post.php
+++ b/api/v3/TwingleSync/Post.php
@@ -55,7 +55,7 @@ function civicrm_api3_twingle_sync_Post($params) {
: $params['twingle_api_key'];
$twingleApi = new TwingleApiCall($apiKey);
- // Get all projects from Twingle and store them in $projects
+ // Get all projects from Twingle
$projects = $twingleApi->getProject();
// Create projects as campaigns if they do not exist and store results in
@@ -68,5 +68,22 @@ function civicrm_api3_twingle_sync_Post($params) {
}
}
+ // Get all events from projects of event type
+ foreach ($result_values['sync']['projects'] as $project) {
+ if ($project['project_type'] == 'event') {
+ $events = $twingleApi->getEvent($project['project_id']);
+ }
+ }
+
+ // Create events them as campaigns if they do not exist and store results in
+ // $result_values
+ $j = 0;
+ if ($events) {
+ foreach ($events as $event) {
+ $result_values['sync']['events'][$j++] = $twingleApi
+ ->syncEvent($event, $is_test);
+ }
+ }
+
return civicrm_api3_create_success($result_values);
}